Go-Micro中含Emoji的消息无法保存的问题解决请求
解决Go-Micro中含Emoji请求的500错误
错误根源
错误提示header key "request" contains value with non-printable ASCII characters,核心原因是Go-Micro的HTTP客户端默认会将Protobuf请求序列化到HTTP Header的X-Micro-Request字段中,而Emoji属于Unicode多字节字符(超出ASCII范围),Go的net/http包会拒绝包含非ASCII字符的Header值,直接导致请求失败。
解决方案(无需修改请求)
1. 配置Go-Micro客户端使用HTTP Body传输请求
修改客户端初始化或服务调用逻辑,强制将请求序列化到HTTP Body而非Header中,这是最安全合规的解决方式:
方式一:全局配置HTTP客户端
import ( "github.com/go-micro/v4/client" "github.com/go-micro/plugins/v4/client/http" "encoding/json" ) // 初始化支持Body传输的HTTP客户端 httpClient := http.NewClient( client.ContentType("application/json"), http.WithRequestEncoder(func(r *http.Request, req interface{}) error { // 将请求序列化为JSON写入Body r.Header.Set("Content-Type", "application/json") return json.NewEncoder(r.Body).Encode(req) }), ) // 将该客户端注入到你的服务客户端实例中 c.App.Promo = promo.NewPromoService("promo-service", httpClient)
方式二:调用服务时临时指定客户端选项
如果不想全局修改客户端,可在单次服务调用时单独配置:
import ( "github.com/go-micro/v4/client" "github.com/go-micro/plugins/v4/client/http" ) // 创建临时HTTP客户端 tempClient := http.NewClient( http.WithRequestEncoder(func(r *http.Request, v interface{}) error { r.Header.Set("Content-Type", "application/json") return json.NewEncoder(r.Body).Encode(v) }), ) // 调用服务时传入该客户端选项 rsp, err := c.App.Promo.PromosValidateUserRecipient(ctx, req, client.WithClient(tempClient))
2. (备选)服务端网关允许非ASCII Header值(不推荐)
如果因特殊需求必须通过Header传输,可修改API网关的HTTP服务器配置,跳过Header的ASCII验证,但这种方式存在安全风险,仅作为应急方案:
import "net/http" // 自定义中间件,允许请求Header中的非ASCII字符(以echo框架为例) e.Use(func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // 跳过Go默认的Header ASCII校验逻辑 c.Request().Header.Del("request") // 重新解析原始Header(需根据网关实际实现调整) rawHeaders := c.Request().Header.Clone() c.Request().Header = rawHeaders return next(c) } })
验证
修改完成后,发送含Emoji的测试请求,确认请求能正常到达服务端,Protobuf的bytes类型原生支持Unicode字符,只要传输过程不被Header拦截,就能正常解析并存储。
内容的提问来源于stack exchange,提问作者Rafi Azzaky
相关产品推荐
相关产品推荐

