Skip to content

fix(grpc-gateway): support application/json and wildcard marshaler in ServeMux#39

Merged
XinxinAkuma merged 1 commit intomainfrom
fix/content-type-marshaler
Mar 18, 2026
Merged

fix(grpc-gateway): support application/json and wildcard marshaler in ServeMux#39
XinxinAkuma merged 1 commit intomainfrom
fix/content-type-marshaler

Conversation

@gangcaiyoule
Copy link
Collaborator

@gangcaiyoule gangcaiyoule commented Mar 18, 2026

背景
线上偶发报错:Failed to parse Content-Type: mime: no media type。
原因是网关只配置了 application/jsonpb,当客户端使用 application/json 或未明确传递内容协商头时,可能匹配失败。

本次修改
在网关 ServeMux 中新增 application/json 的 marshaler 配置
保留 application/jsonpb 的 marshaler 配置
新增 MIMEWildcard 兜底 marshaler,兼容未显式声明内容类型的请求
预期效果
支持 application/json 请求
支持 application/jsonpb 请求
在未显式传递 Accept/Content-Type 时仍可正常处理
避免再次出现 Content-Type 解析失败问题

Summary by CodeRabbit

发布说明

  • 改进
    • 优化了 API 响应序列化处理机制,增强了 JSON 格式的标准化处理。
    • 改进了对未指定 Content-Type 请求的默认处理支持。

@coderabbitai
Copy link

coderabbitai bot commented Mar 18, 2026

演练

此pull request对.gitignore文件和gRPC Gateway的mux配置进行了更改。在.gitignore中添加了test_marshaler.go条目,在mux.go中为JSON和JSONPb添加了新的marshaler配置选项,包括默认的MIME通配符处理。

变更

Cohort / File(s) 摘要
构建配置
.gitignore
添加test_marshaler.go到忽略列表。
gRPC Gateway Marshaler配置
api/grpc_gateway/mux.go
为application/json添加标准JSON marshaler,配置EmitUnpopulated=true、UseProtoNames=true、DiscardUnknown=false。保留现有application/jsonpb marshaler。引入新的默认marshaler选项,使用MIMEWildcard处理未指定Content-Type的客户端请求,采用相同的JSONPb选项。

代码审查工作量评估

🎯 2 (简单) | ⏱️ ~10 分钟

🐰 在marshaler的舞蹈中,
JSON格式各显风采,
默认处理更添温柔,
配置增强无损转化,
gitignore一行小调整,
微小之变促大进步。

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确反映了主要变更内容,即在gRPC网关ServeMux中添加application/json和通配符marshaler的支持。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/content-type-marshaler
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

Migrating from UI to YAML configuration.

Use the @coderabbitai configuration command in a PR comment to get a dump of all your UI settings in YAML format. You can then edit this YAML file and upload it to the root of your repository to configure CodeRabbit programmatically.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
api/grpc_gateway/mux.go (1)

26-54: 建议提取共享的 marshaler 配置以减少重复代码。

三个 marshaler 使用完全相同的 MarshalOptionsUnmarshalOptions 配置,可以提取为共享变量以提高可维护性。

♻️ 重构建议:提取共享配置
+var defaultJSONPb = &runtime.JSONPb{
+	MarshalOptions: protojson.MarshalOptions{
+		EmitUnpopulated: true,
+		UseProtoNames:   true,
+	},
+	UnmarshalOptions: protojson.UnmarshalOptions{
+		DiscardUnknown: false,
+	},
+}
+
 var DefaultServeMuxOption = []runtime.ServeMuxOption{
 	runtime.WithErrorHandler(DefaultErrorHandler),
 	runtime.WithRoutingErrorHandler(DefaultRoutingErrorHandler),
 	runtime.WithIncomingHeaderMatcher(DefaultHeaderWarp),
 	// 标准 JSON 格式
-	runtime.WithMarshalerOption("application/json", &runtime.JSONPb{
-		MarshalOptions: protojson.MarshalOptions{
-			EmitUnpopulated: true,
-			UseProtoNames:   true,
-		},
-		UnmarshalOptions: protojson.UnmarshalOptions{
-			DiscardUnknown: false,
-		},
-	}),
+	runtime.WithMarshalerOption("application/json", defaultJSONPb),
 	// Protobuf JSON 格式
-	runtime.WithMarshalerOption("application/jsonpb", &runtime.JSONPb{
-		MarshalOptions: protojson.MarshalOptions{
-			EmitUnpopulated: true,
-			UseProtoNames:   true,
-		},
-		UnmarshalOptions: protojson.UnmarshalOptions{
-			DiscardUnknown: false,
-		},
-	}),
+	runtime.WithMarshalerOption("application/jsonpb", defaultJSONPb),
 	// 兜底方案:客户端没明确指定 Content-Type 时用这个
-	runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.JSONPb{
-		MarshalOptions: protojson.MarshalOptions{
-			EmitUnpopulated: true,
-			UseProtoNames:   true,
-		},
-		UnmarshalOptions: protojson.UnmarshalOptions{
-			DiscardUnknown: false,
-		},
-	}),
+	runtime.WithMarshalerOption(runtime.MIMEWildcard, defaultJSONPb),
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/grpc_gateway/mux.go` around lines 26 - 54, The three
runtime.WithMarshalerOption calls in mux.go repeat identical runtime.JSONPb
settings; extract the common runtime.JSONPb (or its
MarshalOptions/UnmarshalOptions) into a single shared variable (e.g., baseJSONPb
or jsonPBOptions) and reuse it in the calls to runtime.WithMarshalerOption for
"application/json", "application/jsonpb", and runtime.MIMEWildcard; update the
existing calls that currently construct a new &runtime.JSONPb with
protojson.MarshalOptions and protojson.UnmarshalOptions to reference the shared
variable instead and ensure the variable is defined near the top of the mux
setup (so functions creating the mux can reuse it).
.gitignore (1)

3-3: 建议确认忽略 test_marshaler.go 的必要性。

忽略根目录下的 .go 文件不太常见。如果这是用于本地调试的临时文件,建议考虑:

  1. 将其移动到独立的测试目录或使用 _test.go 后缀
  2. 或者在 PR 中说明该文件的用途
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.gitignore at line 3, 当前 .gitignore 把根目录下的 test_marshaler.go
忽略了,请确认是否真的需要忽略该文件:如果这是临时/本地调试文件,建议将 test_marshaler.go 移到一个独立目录或重命名为以 _test.go
结尾(便于 go 工具识别);如果该文件必须保留在根目录且不应被忽略,则从 .gitignore 中移除 test_marshaler.go;若保留忽略,请在
PR 描述中说明 test_marshaler.go 的用途以便审阅者理解。
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@api/grpc_gateway/mux.go`:
- Around line 31-33: The protojson UnmarshalOptions currently sets
DiscardUnknown: false which causes JSON unmarshal to fail on unknown fields;
update the protojson.UnmarshalOptions used to configure the HTTP->gRPC JSON
parsing (the UnmarshalOptions block) to set DiscardUnknown: true if you want
forward-compatibility so new/unknown fields in requests are ignored, or
explicitly document/keep false if strict rejection of unknown fields is
intended; change the DiscardUnknown value on the UnmarshalOptions struct
accordingly.

---

Nitpick comments:
In @.gitignore:
- Line 3: 当前 .gitignore 把根目录下的 test_marshaler.go
忽略了,请确认是否真的需要忽略该文件:如果这是临时/本地调试文件,建议将 test_marshaler.go 移到一个独立目录或重命名为以 _test.go
结尾(便于 go 工具识别);如果该文件必须保留在根目录且不应被忽略,则从 .gitignore 中移除 test_marshaler.go;若保留忽略,请在
PR 描述中说明 test_marshaler.go 的用途以便审阅者理解。

In `@api/grpc_gateway/mux.go`:
- Around line 26-54: The three runtime.WithMarshalerOption calls in mux.go
repeat identical runtime.JSONPb settings; extract the common runtime.JSONPb (or
its MarshalOptions/UnmarshalOptions) into a single shared variable (e.g.,
baseJSONPb or jsonPBOptions) and reuse it in the calls to
runtime.WithMarshalerOption for "application/json", "application/jsonpb", and
runtime.MIMEWildcard; update the existing calls that currently construct a new
&runtime.JSONPb with protojson.MarshalOptions and protojson.UnmarshalOptions to
reference the shared variable instead and ensure the variable is defined near
the top of the mux setup (so functions creating the mux can reuse it).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8c77f9d2-096e-43eb-b45c-f1d6cccaa95e

📥 Commits

Reviewing files that changed from the base of the PR and between ef01eb4 and 49083c7.

📒 Files selected for processing (2)
  • .gitignore
  • api/grpc_gateway/mux.go

Comment on lines +31 to +33
UnmarshalOptions: protojson.UnmarshalOptions{
DiscardUnknown: false,
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

DiscardUnknown: false 会拒绝包含未知字段的请求。

当设置为 false 时,如果请求 JSON 中包含 proto 定义中不存在的字段,反序列化将失败。这比默认行为更严格。

请确认这是预期行为。如果希望保持向前兼容性(允许客户端发送新字段而旧服务端忽略),建议设置为 true

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@api/grpc_gateway/mux.go` around lines 31 - 33, The protojson UnmarshalOptions
currently sets DiscardUnknown: false which causes JSON unmarshal to fail on
unknown fields; update the protojson.UnmarshalOptions used to configure the
HTTP->gRPC JSON parsing (the UnmarshalOptions block) to set DiscardUnknown: true
if you want forward-compatibility so new/unknown fields in requests are ignored,
or explicitly document/keep false if strict rejection of unknown fields is
intended; change the DiscardUnknown value on the UnmarshalOptions struct
accordingly.

@XinxinAkuma XinxinAkuma merged commit eb00df8 into main Mar 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants