Skip to content

http 服务

创建一个 http server

go
httpServer := luchen.NewHTTPServer(
    "helloworld",
    luchen.WithHTTPAddr(":8080"),
)

可选参数

go
// NewHTTPServer 创建 http server
// opts 查看 ServerOptions
func NewHTTPServer(opts ...ServerOption) *HTTPServer

// ServerOptions server 选项
type ServerOptions struct {
    serviceName string
    addr        string
    metadata    map[string]any
}

// WithServiceName server 名称,在微服务中作为一组服务名称标识,单体服务则无需关注
func WithServiceName(serviceName string) ServerOption
// WithServerAddr server 监听地址
func WithServerAddr(addr string) ServerOption
// WithServerMetadata server 注册信息 metadata,单体服务无需关注
func WithServerMetadata(md map[string]any) ServerOption

路由和端点绑定

handler 接口定义

go
// HTTPHandler http 请求处理器接口
type HTTPHandler interface {
	// Bind 绑定路由
	Bind(router *HTTPServeMux)
}

示例

go
type helloHandler struct {
}

func (h *helloHandler) Bind(router *luchen.HTTPServeMux) {
    router.Handle("/say-hello", h.sayHello())
}

func (h *helloHandler) sayHello() *httptransport.Server {
    return luchen.NewHTTPTransportServer(
        makeSayHelloEndpoint(), // 端点绑定,端点的定义在下面说明
        decodeSayHello,
        encodeSayHello,
    )
}

注册路由

go
handler := &helloHandler{}
httpServer.Handler(
    handler,
)

中间件

接口定义

go
// HTTPMiddleware http 请求中间件
type HTTPMiddleware func(http.Handler) http.Handler

示例:实现提个请求耗时打印中间件

go
func timeMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		requestURI := r.RequestURI
		start := time.Now()
		defer func() {
			log.Infof("take time: %s, %v", requestURI, time.Since(start))
		}()
		next.ServeHTTP(w, r)
	})
}

使用中间件

go
httpServer.Use(
    timeMiddleware,
)

在子路由中使用中间件

go
// 为子路由添加中间件
router.Sub("/log", func(sub *luchen.HTTPServeMux) {
    sub.Use(logMiddleware)
    sub.Handle("/say-hello", h.sayHello()) // curl http://localhost:8080/log/say-hello?name=fjx
})


// 打印日志
func logMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.InfofCtx(r.Context(), "request %s", r.RequestURI)
        next.ServeHTTP(w, r)
    })
}

端点绑定

go
// 端点定义,端点即对应一个接口,不同协议转换成相同的参数,交给端点进行处理
func makeSayHelloEndpoint() kitendpoint.Endpoint {
    return func(ctx context.Context, request interface{}) (response interface{}, err error) {
        name := request.(string)
        response = "hello: " + name
        return
    }
}

// 处理http协议参数解码
func decodeSayHello(_ context.Context, r *http.Request) (interface{}, error) {
    name := r.URL.Query().Get("name")
    return name, nil
}

// 处理http协议响应参数编码
func encodeSayHello(_ context.Context, w http.ResponseWriter, resp interface{}) error {
    _, err := w.Write([]byte(resp.(string)))
    return err
}

参数编解码

通过编解码处理将不同协议转换为统一的结构体,交给 endpoint 处理。

接口定义在:https://github.com/go-kit/kit/blob/master/transport/http/encode_decode.go

go
// http 请求参数解码
type DecodeRequestFunc func(context.Context, *http.Request) (request interface{}, err error)

// http 响应参数编码
type EncodeRequestFunc func(context.Context, *http.Request, interface{}) error

luchen 内置了一些 http 协议的请求和响应参数编解码方法,如不满足需求,可以自己实现编解码接口。

解码

go
// DecodeParamHTTPRequest 解析 http request query 和 form 参数
func DecodeParamHTTPRequest[T any](ctx context.Context, r *http.Request) (interface{}, error)

// DecodeJSONRequest 解析 http request body json 参数
func DecodeJSONRequest[T any](ctx context.Context, r *http.Request) (interface{}, error)

编码

go
// EncodeHTTPJSONResponse http 返回json数据
// wrapper 对数据重新包装
func EncodeHTTPJSONResponse(wrapper DataWrapper) httptransport.EncodeResponseFunc

静态文件服务

go
// 注册静态文件服务访问路径和文件路径
httpServer.Static("/assets/", "static")

示例源码

完整示例代码:feathttp