mirror of
https://github.com/zap-proto/zip.git
synced 2026-10-19 15:38:57 +00:00
AdaptNetHTTP handed the stdlib handler fiber's adaptor writer, which gathers the whole body and copies it out when the handler returns. For an ordinary reply that is only a buffer. For server-sent events it is the difference between a stream and one delivery at the end — a caller watching tokens arrive sees nothing until the answer is already complete, which looks exactly like a slow model and is why "streaming works" could be true and useless at the same time. The handler now runs against a pipe, and the pipe is synchronous: a Write does not return until the reader has taken the bytes, which is what makes Flush honest rather than a stub. Status and headers are read from the handler's first act and applied before the body streams, because fasthttp writes them once and cannot revise them afterwards. Tested over a real socket, not the in-memory helper — that helper collects the whole response, so it cannot tell a stream from a buffer. Co-authored-by: Hanzo Dev <[email protected]>
65 lines
2.7 KiB
Go
65 lines
2.7 KiB
Go
// Adapters for bringing existing net/http code onto zip
|
|
// without rewriting handlers. These are MIGRATION TOOLS — each adapter
|
|
// costs ~5% perf vs native Fiber dispatch and exists so a service can
|
|
// roll onto zip incrementally. Replace adapted routes with native
|
|
// zip handlers when feasible.
|
|
|
|
package zip
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/zap-proto/fiber/v3/middleware/adaptor"
|
|
)
|
|
|
|
// AdaptNetHTTP wraps an http.Handler so it can be served on a zip router as an
|
|
// ordinary zip.Handler. To front a whole foreign subtree, take a Group for the
|
|
// prefix and register a wildcard on it — this is THE way to bring net/http code
|
|
// onto zip:
|
|
//
|
|
// app.Group("/legacy").All("/*", zip.AdaptNetHTTP(httpHandler))
|
|
//
|
|
// Group is what carries the prefix; Proxy does not do this. Proxy delegates a
|
|
// prefix to a REMOTE address over a transport, so it takes a string, not a
|
|
// handler. A local handler is composed, not delegated.
|
|
//
|
|
// The wildcard stays an ordinary route, so most-specific-wins precedence still
|
|
// applies: a route registered on the group afterwards still beats it for its
|
|
// exact path.
|
|
//
|
|
// g := app.Group("/legacy")
|
|
// g.All("/*", zip.AdaptNetHTTP(httpHandler)) // everything else
|
|
// g.Get("/health", nativeHealth) // still wins
|
|
//
|
|
// A bare func is adapted through http.HandlerFunc, which is itself an
|
|
// http.Handler — there is no separate func-shaped adapter:
|
|
//
|
|
// app.Get("/legacy", zip.AdaptNetHTTP(http.HandlerFunc(myFunc)))
|
|
//
|
|
// Migration tool — costs ~5% perf vs native Fiber. Replace with native
|
|
// zip handlers when feasible.
|
|
func AdaptNetHTTP(h http.Handler) Handler {
|
|
// Streams — see adapt_stream.go. ONE adapter rather than a buffering one and
|
|
// a streaming one, because "which adapter did this route get" is exactly the
|
|
// question nobody should have to ask to explain why server-sent events
|
|
// arrive all at once on one mount and incrementally on another.
|
|
//
|
|
// TERMINAL: an http.Handler writes the response, so this answers whatever
|
|
// address it is registered at. In Use position it would answer every one of
|
|
// them, which is why the wildcard route above is THE spelling and this is
|
|
// refused at build time — see [Terminal].
|
|
return Terminal("zip.AdaptNetHTTP", adaptStreaming(h))
|
|
}
|
|
|
|
// AdaptNetHTTPMiddleware wraps a stdlib middleware (func(http.Handler) http.Handler)
|
|
// as a zip.Handler — the net/http-middleware bridge. Because it IS middleware,
|
|
// it goes on a Group's Use rather than on a route:
|
|
//
|
|
// app.Group("/legacy").Use(zip.AdaptNetHTTPMiddleware(mw))
|
|
//
|
|
// Migration tool — costs ~5% perf vs native Fiber.
|
|
func AdaptNetHTTPMiddleware(mw func(http.Handler) http.Handler) Handler {
|
|
wrapped := adaptor.HTTPMiddleware(mw)
|
|
return func(c *Ctx) error { return wrapped(c.fc) }
|
|
}
|