feat: add HTTP migration bridges and extensible API binding

This commit is contained in:
2026-09-24 01:47:42 +08:00
parent 7b8eca1a61
commit a8c973d8a2
39 changed files with 2596 additions and 118 deletions

View File

@@ -3,6 +3,7 @@ package httpx
import (
"context"
"encoding/json"
"errors"
"net/http"
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
@@ -101,12 +102,15 @@ func NewContext(request *http.Request, writer http.ResponseWriter, params map[st
if request == nil {
request = &http.Request{}
}
return &Context{
c := &Context{
request: request,
writer: writer,
params: params,
values: make(map[string]any),
}
if writer != nil {
c.writer = trackWriter(writer, c)
}
return c
}
func (c *Context) Request() *http.Request { return c.request }
@@ -120,8 +124,8 @@ func (c *Context) Context() context.Context {
return c.request.Context()
}
// Raw returns the response writer supplied by the active network adapter.
// Prefer the transport-neutral methods on Context for portable handlers.
// Raw returns a streaming response writer that tracks commits and status.
// Optional HTTP capabilities are preserved only when the underlying writer supports them.
func (c *Context) Raw() http.ResponseWriter { return c.writer }
// Clone gives a buffering middleware its own response state and values map.
@@ -146,7 +150,6 @@ func (c *Context) WriteResponse(status int, headers http.Header, body []byte) er
for key, values := range headers {
c.writer.Header()[key] = append([]string(nil), values...)
}
c.responded, c.status = true, status
c.writer.WriteHeader(status)
if len(body) > 0 {
if _, err := c.writer.Write(body); err != nil {
@@ -216,8 +219,6 @@ func (c *Context) JSON(status int, value any) error {
if err != nil {
return apierrors.Internal(err)
}
c.responded = true
c.status = status
c.writer.Header().Set("Content-Type", "application/json; charset=utf-8")
c.writer.WriteHeader(status)
if _, err := c.writer.Write(append(data, '\n')); err != nil {
@@ -243,8 +244,6 @@ func (c *Context) NoContent() error {
if c.writer == nil {
return apierrors.Internal(nil)
}
c.responded = true
c.status = http.StatusNoContent
c.writer.WriteHeader(http.StatusNoContent)
return nil
}
@@ -271,12 +270,15 @@ func (c *Context) Status() int {
func (c *Context) Responded() bool { return c.responded }
// WriteError writes a stable public error response. Internal causes are not
// serialized. Responses committed through Context methods are preserved;
// direct Raw writes are outside this response-tracking contract.
// serialized. Responses committed through Context methods or Raw are preserved.
func (c *Context) WriteError(err error) {
if c.responded || err == nil {
return
}
var bodyErr *http.MaxBytesError
if errors.As(err, &bodyErr) {
err = bodyTooLarge()
}
apiErr := apierrors.From(err)
if writeErr := c.writeResult(response.Result{
Status: apiErr.Status,