Yii2框架jQuery POST请求返回400 Bad Request错误如何解决
Yii2 多语言切换POST请求400错误修复方案
核心原因
Yii2框架默认开启全局POST请求的CSRF跨站请求伪造校验,你的前端AJAX请求没有携带框架要求的CSRF校验令牌,会被框架直接拦截返回400状态码,这是Yii2开发中POST请求报400的最高频原因。同时你的前后端代码还存在几处语法和逻辑bug,一并修复即可正常运行。
具体修复步骤
- 修正前端jQuery代码
你原来的JS代码存在三个问题:最后多了一个多余的闭合大括号会触发语法错误、用全局选择器拿语言值永远只会取第一个语言选项的id、多余的JSON.stringify会把语言值包成多余的带引号字符串、缺少CSRF校验参数。替换为如下代码即可:
$(document).on('click','.language',function() { // 取当前点击元素的id作为语言值,不需要JSON序列化 var lang = $(this).attr('id'); console.log("当前选中语言:" + lang); $.post('language', { 'lang': lang, // 携带Yii2要求的CSRF校验参数,方法由Yii框架自带的前端资源提供 [yii.getCsrfParam()]: yii.getCsrfToken() }, function() { location.reload(); }); });
- 修正后端控制器代码
你原来的PHP代码里误用了JS的console.log()语法,会触发PHP语法错误,同时缺少语言值合法性校验、cookie过期时间设置,也没有给前端返回正常响应。替换为如下代码:
public function actionLanguage() { if (Yii::$app->request->isPost && $lang = Yii::$app->request->post('lang')) { // 配置你项目实际支持的语言白名单,避免传入非法值 $allowedLanguages = ['zh-CN', 'en-US']; if (in_array($lang, $allowedLanguages)) { Yii::$app->language = $lang; $cookie = new yii\web\Cookie([ 'name' => 'lang', 'value' => $lang, 'expire' => time() + 86400 * 365, // cookie有效期1年,避免关闭浏览器就失效 ]); Yii::$app->response->cookies->add($cookie); } } // 处理完成后跳回来源页,比前端强制reload兼容性更好 return $this->redirect(Yii::$app->request->referrer); }
安全提示:关闭CSRF校验会让接口暴露在跨站请求伪造风险下,优先使用携带CSRF参数的方案。
- (不推荐)可选方案:单独关闭该接口的CSRF校验
如果你不想在前端传CSRF参数,可以在对应控制器里把这个接口加入CSRF校验白名单:
public function beforeAction($action) { if ($action->id === 'language') { $this->enableCsrfValidation = false; } return parent::beforeAction($action); }
内容的提问来源于stack exchange,提问作者Paul Stokvinsky
相关产品推荐
相关产品推荐

