zbchi opened a new pull request, #3301:
URL: https://github.com/apache/dubbo-go/pull/3301

   ## Description
   
    #2847.
   
      Add a minimal, transport-scoped way to host an existing root 
`http.Handler` on the Triple listener.
   
     This change does not try to turn plain HTTP into a first-class dubbo-go 
service model in one step. It focuses on the transport-layer integration needed 
to make incremental HTTP-to-Triple migration possible.
   
     With this change:
   
     - an existing HTTP service can be hosted on the same listener as Triple
     - both `mount-first` and `export-first` flows are supported
     - HTTP-only startup on a Triple listener is supported
     - Triple routes still take priority over mounted HTTP traffic
     - mounted HTTP traffic acts as a transport-level fallback after Triple 
route lookup
   
     ## Design
   
     ### 1. Add an optional protocol capability
   
     Mounting an existing HTTP handler is not a generic server configuration 
concern.
     It is only meaningful for protocols that are actually implemented on top 
of `net/http`.
   
     For that reason, this PR introduces an optional protocol capability 
instead of pushing an `http.Handler` into generic config structs:
   
     ```go
     type HTTPHandlerMountable interface {
        MountHTTPHandler(url *common.URL, handler http.Handler) error
     }
     ```
     This keeps HTTP mounting scoped to protocols that can actually host HTTP
     traffic, rather than leaking transport-specific runtime state into generic
     server configuration.
   
     ### 2. Model mounting as a single root handler
   
     Mounting is intentionally modeled as a single root http.Handler.
   
     That decision is deliberate. dubbo-go owns one shared listener, while 
plain HTTP route composition should remain in user space. If a caller needs to 
expose multiple HTTP services, they can compose them behind their own 
http.ServeMux
     or router and mount that mux once.
   
     This keeps the boundary clear:
   
     dubbo-go owns listener lifecycle and Triple routing
     user code owns plain HTTP route composition
   
     ### 3. Reuse Triple as the transport host
   
     This pr makes mount-first and export-first converge on the same shared
     listener lifecycle.
   
     This allows:
   
     1. mounting an HTTP handler first, then exporting Triple services later
     2. exporting Triple services first, then mounting an HTTP fallback later
     3. running a mounted HTTP service on a Triple listener even when no Triple 
service is exported yet
   
     This avoids introducing a separate startup model just for mounted HTTP 
traffic.
   
     ### 4. Preserve Triple route priority
   
     Mounted HTTP traffic is intentionally implemented as a transport-level 
fallback,
     not as a competing routing layer.
   
     The route mux resolves requests in this order:
   
     1. exact Triple procedure match
     2. method-name case-adapted Triple fallback
     3. mounted HTTP fallback
   
     A simplified version of the serving logic is:
   
   ```go
     func (m *methodRouteMux) ServeHTTP(w http.ResponseWriter, r *http.Request) 
{
        handler, pattern := m.Handler(r)
        if pattern != "" {
                handler.ServeHTTP(w, r)
                return
        }
        if fallback := m.fallback; fallback != nil {
                fallback.ServeHTTP(w, r)
                return
        }
        http.NotFound(w, r)
     }
   ```
     This ordering is important: mounting an existing HTTP service must not 
preempt
     registered Triple procedures on the same listener.
   
     ### 5. Validate listener-fixed transport settings
   
     When the same Triple listener is reused, transport-level settings must 
remain
     consistent.
   
     This pr validates and rejects conflicts for listener-fixed settings such 
as:
   
     HTTP/2 vs HTTP/3 transport mode
     TLS configuration
   
     Handler-level Triple options may still vary per exported service.
   
   ## Usage
   ```go
        mux := http.NewServeMux()
        mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) 
{
                _, _ = w.Write([]byte("ok"))
        })
        mux.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
                _, _ = w.Write([]byte("ready"))
        })
   
        srv, err := server.NewServer(
                server.WithServerProtocol(
                        protocol.WithPort(20000),
                        protocol.WithTriple(),
                ),
        )
        if err != nil {
                panic(err)
        }
   
        if err := srv.MountHTTPHandler(mux); err != nil {
                panic(err)
        }
   
        // Triple services can still be registered as usual before Serve.
   
        if err := srv.Serve(); err != nil {
                panic(err)
        }
   ```
   ## Checklist
   
     - [x] I confirm the target branch is develop
     - [x] Code has passed local testing
     - [x] I have added tests that prove my fix is effective or that my feature 
works
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to