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

推荐订阅源

aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
博客园 - 司徒正美
L
LangChain Blog
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
Stack Overflow Blog
Stack Overflow Blog
Engineering at Meta
Engineering at Meta
U
Unit 42
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
博客园 - 叶小钗
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
月光博客
月光博客
量子位
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
D
DataBreaches.Net

希仁之拥

领克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))
    }
...