c.JSONP()返回JavaScript而非JSON,因其本质是将数据包装为callback({"key":"value"})形式的可执行JS代码,Content-Type设为application/javascript,专供<script>标签跨域加载执行,不适用于fetch/axios等现代API请求。

为什么c.JSONP()调用后返回的是JavaScript而不是JSON
c.JSONP()不是“加个P的JSON”,而是专门用于绕过浏览器同源策略的跨域响应机制。它会把数据包装进一个函数调用里,比如 callback({"name":"Alice"}),Content-Type 也是 application/javascript,不是 application/json。如果你在前端用 fetch 或 axios 请求它,会直接报 MIME 类型不匹配错误——因为现代浏览器拒绝执行非 script 标签加载的 JS 响应。
- 只应在
<script src="/api/data?callback=handleData"></script>这种场景下使用 - 必须带
callback查询参数,否则c.JSONP()会 fallback 到普通 JSON(Gin v1.9+ 默认返回 400) - 函数名只能是字母、数字、下划线、美元符;含点号、中划线、空格等会触发
http.StatusBadRequest - 不校验函数名是否已在前端定义,也不做 CSP 兼容处理
c.JSONP() 的参数和结构体字段注意事项
和 c.JSON() 不同,c.JSONP() 对结构体字段没有额外要求:不需要 json:"field" tag,导出/非导出字段也照常序列化(只要能被 Go 的 encoding/json 序列化)。但它仍受 json 包规则约束:
- 匿名字段不会自动提升,除非显式加
json:",inline" - 非导出字段(小写首字母)默认被忽略,即使加了 tag
- 如果传入
nil或未初始化的 map/slice,输出为null,不是空对象或空数组 - 不支持自定义时间格式,
time.Time仍按 RFC3339 输出(如"2026-09-05T18:37:00Z")
如何避免 JSONP 接口被滥用或误用
JSONP 天然缺乏请求身份校验能力,且无法携带 Cookie(除非显式设置 withCredentials: true,但 script 标签不支持),所以它不适合传输敏感数据。常见防护手段包括:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
- 限制 callback 参数长度(建议 ≤ 64 字符),防止注入恶意 JS 片段
- 白名单校验 callback 函数名:例如只允许
^handle[A-Z0-9_]+$ - 禁用 GET 以外的方法:JSONP 只能走 GET,路由注册时别漏掉
r.POST("/jsonp", ...)这类冗余入口 - 不与 JWT、session 等状态机制混用;若需鉴权,改用 CORS + Bearer Token
替代方案比强行用 JSONP 更值得考虑
除非你明确要支持 IE8/9 或老旧嵌入式设备,否则优先用标准 CORS。Gin 配置一行中间件就能解决:
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://example.com"},
AllowMethods: []string{"GET", "POST"},
AllowHeaders: []string{"Authorization", "Content-Type"},
ExposeHeaders: []string{"X-Total-Count"},
AllowCredentials: true,
}))
JSONP 是历史包袱,不是优雅设计。真正容易被忽略的是:一旦上线 JSONP 接口,就等于向任意域名开放了无凭证的数据读取通道——哪怕你加了 referer 检查,也能被伪造。别为了“兼容性”牺牲安全边界。

















