return jsonp($data) 没生效是因为 jsonp() 是硬终止型响应,内部调用 exit,若未 return 或后续有其他逻辑,将被跳过;必须确保请求带合法 callback 参数、tp6+ 需注册 jsonp 中间件,并避免 nginx 缓存忽略 $args。

return jsonp($data) 为什么没生效
不是函数写错了,是它根本没走到输出环节。ThinkPHP 的 jsonp() 是“硬终止型”响应,内部调用 exit,所以如果你在控制器里写了 jsonp($data) 却没加 return,或者后面还跟着日志、跳转、DB 操作,那它就直接被跳过了。
常见错误现象包括:响应体是纯 JSON(不是 callback({...}))、浏览器控制台报 Uncaught SyntaxError: Unexpected token、或压根没返回内容。
- 必须写成
return jsonp($data),不能只调用不 return - 确保请求 URL 带了
?callback=xxx,jsonp()默认只读$_GET['callback'],不认 POST 或 header - 回调名必须合法:只允许字母、数字、下划线、点号、括号;超长(>32 字符)、含斜杠或空格会静默失败,返回空响应
- ThinkPHP 6.0+ 默认禁用 JSONP,需在
app/middleware.php中手动注册think\middleware\Jsonp::class
怎么让 JSONP 响应带跨域头或自定义状态码
jsonp() 助手函数不支持链式设置 header 或 code,它的设计就是“开箱即用但不可扩展”。想加 Access-Control-Allow-Origin 或返回 400 状态码,得绕过它,手动构造。
核心三件事:设对 Content-Type、拼对 JS 调用格式、立刻终止流程。
- 先校验
$_GET['callback']是否匹配正则/^[a-zA-Z_][a-zA-Z0-9_]*$/,不通过就return response('', 400)->header('Content-Type', 'text/plain') - 用
htmlspecialchars(json_encode($data), ENT_NOQUOTES)防止 JSON 内引号破坏 JS 结构 - 输出时必须写全:
header('Content-Type: application/javascript; charset=utf-8');,不能只靠框架自动推断 - 最后一定要
exit或die,否则 ViewInit 中间件可能追加 HTML 模板
Nginx 下 JSONP 响应总被缓存错乱
这不是 ThinkPHP 的问题,是 Nginx 缓存 key 没包含 callback 参数。默认 proxy_cache_key 只含 URI,不同用户的 ?callback=a 和 ?callback=b 被当成同一个缓存项,结果 A 用户拿到 B 用户的回调名,前端直接报 callback is not defined。
必须显式把请求参数纳入缓存 key:
- 在 Nginx 配置中改
proxy_cache_key,加上$args,例如:"$scheme$request_method$host$request_uri $args" - 避免使用
proxy_cache_bypass $args这类模糊策略,它无法精准区分 callback 差异 - 如果用 CDN,也要检查其缓存规则是否忽略 query string
中文乱码、斜杠变 \/、callback 名被 XSS 利用
这些都不是 jsonp() 函数本身的缺陷,而是底层 json_encode() 行为 + 输入未过滤的组合结果。
- 中文显示为
\uXXXX:TP6 默认不启用JSON_UNESCAPED_UNICODE,需全局配置'json_encode' => [JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES](TP6.1+)或手动拼接时传入该 flag - URL 或 HTML 字符里的
/变成\/:缺JSON_UNESCAPED_SLASHES,同上一配置项补上即可 - 前端执行了恶意脚本:因为没校验 callback 名,攻击者传
?callback=alert(1)//就能触发。务必用白名单正则过滤,别信htmlspecialchars()对函数名的保护——它不阻止 JS 执行
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











