You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2 Controller/Action浏览器下重复触发两次问题求助

排查步骤

先在目标Action开头增加请求日志,确认两次请求的具体信息,排除规则匹配、异常跳转等问题:

public function actionTest()
{
    // 新增日志逻辑
    $logPath = \Yii::getAlias('@console') . '/runtime/request_log_' . date('Ymd') . '.txt';
    $logContent = implode(' | ', [
        date('Y-m-d H:i:s'),
        \Yii::$app->request->getMethod(),
        \Yii::$app->request->getAbsoluteUrl(),
        \Yii::$app->request->getUserAgent(),
        json_encode(\Yii::$app->request->getHeaders()->toArray())
    ]) . PHP_EOL;
    file_put_contents($logPath, $logContent, FILE_APPEND);

    // 原有业务逻辑
    $path = \Yii::getAlias('@console') . '/runtime/';
    $n = 'A__' . self::random_uppercase(2);
    file_put_contents($path . $n . '.txt', time());

    return $this->render('test');
}

触发两次请求后查看日志,可根据请求特征匹配对应解决方案:


常见场景及解决方案

1. 空资源属性导致重复请求(最高发)

如果你的视图/布局文件中存在空的src/href属性,例如<img src="">、<link href="">、<script src="">,绝大多数浏览器会将空地址解析为当前页面URL,自动发起第二次GET请求。
解决方案:

  • 检查所有布局、视图模板,删除无意义的空资源标签,或补全正确的资源地址
  • 单独配置favicon.ico路由,避免浏览器自动请求favicon时被Yii2解析到业务Action,可在web目录下直接放入favicon.ico文件,或在nginx/apache配置中优先处理静态资源请求

2. 浏览器预加载/预渲染请求

新版Chrome、Opera默认开启页面预加载功能,Firefox开启开发者控制台时也可能触发预取逻辑,这类请求会携带专属请求头:Purpose: prefetch、X-Moz: prefetch。
解决方案:
在Controller的beforeAction钩子中拦截预请求,不执行业务逻辑直接返回:

public function beforeAction($action)
{
    $headers = \Yii::$app->request->getHeaders();
    if (
        ($headers->has('Purpose') && $headers->get('Purpose') === 'prefetch')
        || ($headers->has('X-Moz') && $headers->get('X-Moz') === 'prefetch')
    ) {
        \Yii::$app->response->statusCode = 204;
        return false;
    }
    return parent::beforeAction($action);
}

3. HTTP跳转导致重复请求

如果站点配置了HTTP强制跳HTTPS、不带www跳转带www的规则,第一次请求会返回301/302状态码,浏览器自动发起第二次跳转后的请求。
解决方案:

  • 直接使用最终跳转后的地址(如HTTPS地址)测试
  • 优化web服务器跳转规则,避免多余的中间跳转

4. 幂等性兜底方案

如果排查后仍偶发重复请求,可针对业务逻辑加短期锁,保障10秒内同一用户同一Action仅执行一次:

public function actionTest()
{
    $lockKey = 'action_idempotent_' . session_id() . '_' . \Yii::$app->request->getPathInfo();
    // 已持有锁直接返回视图
    if (\Yii::$app->cache->get($lockKey)) {
        return $this->render('test');
    }
    // 加10秒锁
    \Yii::$app->cache->set($lockKey, 1, 10);

    // 原有业务逻辑
    $path = \Yii::getAlias('@console') . '/runtime/';
    $n = 'A__' . self::random_uppercase(2);
    file_put_contents($path . $n . '.txt', time());

    return $this->render('test');
}

内容的提问来源于stack exchange,提问作者Jon C.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 11:57:02