Yii2原生支持JSONP但需手动触发:必须通过GET参数callback显式启用,响应格式设为FORMAT_JSONP并返回含callback和data键的数组,否则回退为普通JSON;ContentNegotiator无法自动识别JSONP。

Yii2 原生支持 JSONP,但需手动触发
Yii2 的 yii\web\Response 类内置了 FORMAT_JSONP 常量,并配有配套的 JsonResponseFormatter,所以 JSONP 不是“加插件才有的功能”,而是框架自带能力。但它不会自动启用——你得显式设置 format 并传入 callback 参数,否则它就当普通 JSON 处理。
- 不设
callback时,哪怕你写了$response->format = \yii\web\Response::FORMAT_JSONP,最终也只输出纯 JSON(因为 formatter 检测不到 callback 就 fallback) -
callback必须来自客户端 GET 参数(如?callback=cb123),不能硬编码或从 POST 读取(JSONP 本质是 script 标签跨域,只走 GET) - Yii2.0.43+ 的
JsonResponseFormatter对 callback 名称做了基础校验(只允许字母、数字、下划线、点、括号),防 XSS,所以别传callback=alert(1)这类恶意值
怎么写一个兼容 JSON / JSONP 的 action
核心是:先取 callback 参数 → 决定响应格式 → 统一组织数据结构 → 交给 Response 自动渲染。不要自己拼字符串,否则绕过 formatter 安全校验,还丢掉 HTTP 头控制权。
- 用
Yii::$app->request->get('callback')获取 callback,别用$_GET - 设置
Yii::$app->response->format为\yii\web\Response::FORMAT_JSON或\yii\web\Response::FORMAT_JSONP,别写死成字符串 - 返回数组时,若用了 JSONP,必须返回包含
callback和data键的数组(这是 Yii 的约定,不是 JS 规范)
public function actionSearch()
{
$callback = Yii::$app->request->get('callback', '');
$result = ['code' => 0, 'msg' => 'ok'];
<pre class="brush:php;toolbar:false;">$format = $callback ? \yii\web\Response::FORMAT_JSONP : \yii\web\Response::FORMAT_JSON;
Yii::$app->response->format = $format;
if ($callback) {
return ['callback' => $callback, 'data' => $result];
}
return $result;}
ContentNegotiator 能不能自动切 JSONP
不能。ContentNegotiator 只认 HTTP 请求头里的 Accept 字段(比如 application/json),而 JSONP 是靠 URL 参数驱动的,和 Accept 无关。它最多帮你拒掉 Accept: application/xml 这类非法请求,但不会因为你传了 callback=xxx 就自动切到 JSONP 模式。
- 如果你强行在
behaviors()里配ContentNegotiator并指定只支持FORMAT_JSON,那 JSONP 请求会直接 406 Not Acceptable - 想做“自动协商”,得自己写个行为或基类方法,在 action 开头统一解析
callback,再动态设 format - 别指望浏览器发
Accept: application/javascript就能触发 JSONP——现实里没人这么发,script 标签根本不带这个头
JSONP 在现代项目里还要不要用
除非你明确要支持 IE8/9 或老版安卓 WebView,否则真没必要。CORS 已是标准,fetch + credentials 配合后端 Access-Control-* 头更安全、更可控。JSONP 没法捕获网络错误、没法设超时、没法读状态码,连基本的错误处理都残缺。
- 如果只是为了解决开发环境跨域,用 Nginx 反向代理或 webpack devServer 的
proxy更干净 - 如果第三方系统强依赖 JSONP(比如某些老旧广告平台回调),那就保留,但务必对
callback参数做白名单过滤,或用正则严格限制字符集 - 注意:Yii2 默认的 JSONP formatter 不处理 Unicode 回调名(比如中文 callback),会出错,这种情况建议直接拒绝或转义处理
真正容易被忽略的是:JSONP 响应永远是 200 OK,哪怕业务逻辑失败,前端也收不到 500 状态码——所有错误都得塞进 data 里靠人工判断。











