应检查content-type头而非仅依赖accept头,用strings.hasprefix(c.get("content-type"), "application/json")判断,不匹配则返回415;需封装为路径/方法敏感的中间件,避免拦截get探针路径。

怎么用 c.Accepts 和 c.Get 检查客户端是否要求 JSON
只靠 Accept 头判断是否“该返回 JSON”是常见误解。Fiber 的 c.Accepts("json") 返回的是客户端声明的首选格式(如 application/json),但它不阻止非 JSON 请求进来——它只是协商结果。真正要“限制只接收 JSON”,重点不在响应格式,而在**拒绝非 JSON 类型的请求体**。
正确做法是检查 Content-Type 请求头,并在不匹配时立即中断:
-
c.Get("Content-Type")获取原始 header 值,注意它可能带参数(如application/json; charset=utf-8) - 用
strings.HasPrefix(c.Get("Content-Type"), "application/json")判断,别用全等比较 - 不满足时直接
return c.Status(415).SendString("Unsupported Media Type"),且不调c.Next()
为什么不能只依赖 c.BodyParser 自动报错
c.BodyParser(&v) 在解析失败时确实会返回 error,但这个 error 是 json.UnmarshalError 或类型不匹配错误,不是 415;它也不会自动设置状态码。你仍需手动捕获并响应,否则默认返回 500 或空响应。
更危险的是:如果前端发来 Content-Type: text/plain 却塞了 JSON 字符串,BodyParser 仍会尝试解析——这违背了“只接收 JSON”的语义,也绕过了媒体类型校验。
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 必须在
BodyParser前做Content-Type检查 - 不要把校验逻辑写在 handler 里,应封装为中间件,统一复用
- 中间件注册要用
app.Post("/api/user", jsonOnly(), handler),而不是app.Use(jsonOnly())全局应用
如何写一个只作用于特定路由的 JSON 限制中间件
Fiber 没有路径模式排除语法,所以中间件内部必须自己判断当前路径和方法。避免误拦 GET /health 这类纯文本端点。
- 中间件函数签名必须是
func(c *fiber.Ctx) error - 先用
c.Method()和c.Path()粗筛(如只对POST+/api/开头的路径生效) - 再检查
Content-Type,不匹配就return c.Status(415).JSON(fiber.Map{"error": "expected application/json"}) - 匹配则
return c.Next(),让后续 handler 执行
示例片段:
func jsonOnly() fiber.Handler {
return func(c *fiber.Ctx) error {
if c.Method() == "POST" && strings.HasPrefix(c.Path(), "/api/") {
ct := c.Get("Content-Type")
if !strings.HasPrefix(ct, "application/json") {
return c.Status(415).JSON(fiber.Map{"error": "unsupported media type"})
}
}
return c.Next()
}
}
容易踩的坑:c.Body() 被提前读导致 BodyParser 失效
如果你在中间件里调了 c.Body()(比如为了日志或调试),那么后续 c.BodyParser() 会读到空 body,因为 fasthttp 的底层 io.ReadCloser 只能读一次。
- 绝对不要在 JSON 限制中间件里调
c.Body()或c.RequestBody() - 如需记录原始 body,得用
c.Request().Body()拷贝一份,再用bytes.NewReader()重置,但代价高,生产环境慎用 - 更稳妥的做法是:限制逻辑只看 header,解析逻辑留给 handler,两者职责分离
最常被忽略的一点:Kubernetes readiness probe 默认发 HTTP GET,若你把 jsonOnly() 错误地挂到 /health/ready 上,整个服务会被标记为不可用——限制逻辑必须严格匹配业务写接口,而非探针路径。










