惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
WordPress大学
WordPress大学
T
Tailwind CSS Blog
V
Visual Studio Blog
月光博客
月光博客
Hugging Face - Blog
Hugging Face - Blog
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
量子位
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
Jina AI
Jina AI
雷峰网
雷峰网
博客园 - 【当耐特】
博客园 - 叶小钗
美团技术团队
宝玉的分享
宝玉的分享
IT之家
IT之家

希仁之拥

领克900半年使用体验 | 希仁之拥的博客 Ubuntu 26.04 Desktop使用体验 | 希仁之拥的博客 【转载】谈谈不受欢迎的博客技术特征 | 希仁之拥的博客 【转载】ClaudeCode 你想知道的所有秘密,源码深度研究报告 | 希仁之拥的博客 2025年年终总结 | 希仁之拥的博客 集成和使用Openclaw后的思考 | 希仁之拥的博客 我买了领克900 | 希仁之拥的博客 服务器性能优化之io拷贝 | 希仁之拥的博客 Go-Sail导航站上线啦 | 希仁之拥的博客 今年国庆的一些感受 [2025] | 希仁之拥的博客 在Deepin 25上配置forticlient | 希仁之拥的博客 分享一些酷酷的站点 [20250908] | 希仁之拥的博客 Go-Sail发布v3.0.6版本了 | 希仁之拥的博客 我对V2EX发布$V2EX讨论的一些感受 | 希仁之拥的博客 如何让Stripe支持支付宝和微信支付 | 希仁之拥的博客 2025上半年里程碑 | 希仁之拥的博客 GitLab+Drone使用体验 | 希仁之拥的博客 四姑娘山之旅 | 希仁之拥的博客 近来帮同事做性能优化的过程回顾 | 希仁之拥的博客 聊聊接口的返回数据结构 | 希仁之拥的博客 由GORM的Updates语法糖 我把 Go-Sail 的文档站更新了 | 希仁之拥的博客 这就是我为什么讨厌拼多多 | 希仁之拥的博客 元旦快乐~ | 希仁之拥的博客 致敬还在写博客的我们 | 希仁之拥的博客 逐步的把图片资源迁移到星光图床上 | 希仁之拥的博客 帮弟弟配了一台mini主机 | 希仁之拥的博客 国庆的一些碎碎念 | 希仁之拥的博客 就这一刻而言,我觉得科技冷冰冰的。 | 希仁之拥的博客 如何使用acme.sh自动续签证书 | 希仁之拥的博客
在goa框架中,如何访问原始请求数据 | 希仁之拥的博客
希仁之拥 · 2021-04-18 · via 希仁之拥

简介

Goa is a Go framework for writing microservices that promotes best practice by providing a single source of truth from which server code, client code, and documentation is derived. The code generated by Goa follows the clean architecture pattern where composable modules are generated for the transport, endpoint, and business logic layers. The Goa package contains middleware, plugins, and other complementary functionality that can be leveraged in tandem with the generated code to implement complete microservices in an efficient manner. By using goa for developing microservices, implementers don’t have to worry about the documentation getting out of sync as Goa takes care of generating OpenAPI specifications for HTTP based services and gRPC protocol buffer files for gRPC based services (or both if the service supports both transports). Reviewers and consumers can also rest assured that the implementation follows the documentation as the code is generated from the same source.

Goa是一个用于编写微服务的Go框架,它通过提供从服务器代码,客户端代码和文档派生的单一事实来源来促进最佳实践。

参考官网文档,可以采用中间件注入上下文的方式来实现额外信息注入。文档地址

  • 首先,按需编写中间件
package middleware

import (
    "bytes"
    "context"
    "io/ioutil"
    "net/http"
)

type CustomContextKey string

const (
    RawRequestWithoutBody CustomContextKey = "x_xx_rawRequest"
    RawBody               CustomContextKey = "x_xxx_rawBody"
)

func InjectRequest() func(http.Handler) http.Handler {
    return func(h http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            ctx := context.WithValue(r.Context(), RawRequestWithoutBody, r)

            //需要单独提取body内容,因为goa层处理的时候,会读取,进而使得下游无法【再次】读取
            body, err := ioutil.ReadAll(r.Body)
            if err == nil {
                r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
            }
            ctx = context.WithValue(ctx, RawBody, body)
            req := r.WithContext(ctx)

            h.ServeHTTP(w, req)
        })
    }
}
  • 然后在服务挂载的地方,将中间件挂载到服务中
import (
    "context"
    "net/http"
    "os"
    "sync"
    "time"

    demoHttpSvr "demo/pkg/api/gen/http/demo/server"
    mdlwr "demo/pkg/middleware"

        ...
)

    var (
        demoSever *demoHttpSvr.Server
    )
    {
        eh := errorHandler(logger)
        demoSever = demoHttpSvr.New(demoEndpoints, mux, dec, enc, eh, mdlwr.GoaErrorFormatterFunc)
        servers := goahttp.Servers{
            demoSever,
        }
        //将中间件挂载到服务中
        servers.Use(mdlwr.InjectRequest())
    }
  • 最后,在需要访问原始请求数据的地方访问
import (
    "context"
    "log"

    mdw "demo/pkg/middleware"

    ...
)

...
    //从上下文中读取
    r, ok := ctx.Value(mdw.RawBody).([]byte)
    if ok {
        log.Println(">>>>>>>>>>>>>>", string(r))
    }
...