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

.htaccess配置重写规则后POST请求数据丢失问题排查

.htaccess重写规则导致POST数据丢失修复

问题背景

站点通过.htaccess配置重定向、重写规则实现去除文件扩展名访问,POST方法提交数据时会在规则处理阶段丢失,单独给重定向规则加非POST判断后问题仍然存在。
当前使用的.htaccess配置:

Options +FollowSymLinks
RewriteEngine  On

RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^resume-.*/([0-9]+)$ /book.php?id=$1 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^channel-books/([0-9]+)/([0-9]+)/([0-9]+)$ /getChannelBooks.php?idChaine=$1&page=$2&orderby=$3 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^channel-books/([0-9]+)/([a-zA-Z]+)$ /getChannelBooks.php?idChaine=$1&$2 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^chaine-.*/([0-9]+)$ /model_contenu_de_chaine.php?idChaine=$1 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^search-([0-9]+)$ /search_page.php?search=$1 [QSA]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^audio-([0-9]+)$ /audiobook.php?id=$1 [QSA]

RewriteRule ^$ /index.php [NC]

RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} \s/([^.]+)\.php [NC]
RewriteRule ^ /%1 [NE,L,R=307]

RewriteRule ^([^\.]+)$ $1.php [NC]

POST请求示例:
POST请求抓包示例
处理用户登出逻辑的destroy_session.php代码如下:

if(isset($_POST['action']) && $_POST['action'] == 'logout'){
   session_unset("username");
   session_destroy();
}

故障原因

  1. 前6条业务路由规则中,搜索、音频详情、首页的三条规则漏加L(last)标记,规则匹配完成后不会终止重写流程,会继续向下匹配最后一条追加.php后缀的规则,触发二次重写。
  2. 最后一条无后缀路径追加.php的内部重写规则,没有加文件/目录/软链接存在性校验,也没有加L标记,会导致重写循环,Apache检测到循环后会自动触发外部重定向,POST数据在外部跳转过程中被丢弃。
  3. 仅给.php转无后缀的307跳转规则加POST判断不足以覆盖所有重写场景,内部重写的循环问题没有被拦截。

修复后的配置

直接替换原有.htaccess内容即可:

Options +FollowSymLinks
RewriteEngine  On

RewriteBase /

# 业务路由规则 全部补全L标记,匹配后立即终止重写
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^resume-.*/([0-9]+)$ /book.php?id=$1 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^channel-books/([0-9]+)/([0-9]+)/([0-9]+)$ /getChannelBooks.php?idChaine=$1&page=$2&orderby=$3 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^channel-books/([0-9]+)/([a-zA-Z]+)$ /getChannelBooks.php?idChaine=$1&$2 [QSA,L]


RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^chaine-.*/([0-9]+)$ /model_contenu_de_chaine.php?idChaine=$1 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^search-([0-9]+)$ /search_page.php?search=$1 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^audio-([0-9]+)$ /audiobook.php?id=$1 [QSA,L]

RewriteRule ^$ /index.php [NC,L]

# 仅非POST请求触发.php到无后缀的307跳转,保留POST请求数据
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} \s/([^.]+)\.php [NC]
RewriteRule ^ /%1 [NE,L,R=307]

# 无后缀路径追加.php的内部重写,补全资源存在校验+L标记,避免重写循环
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^([^\.]+)$ $1.php [NC,L]

测试注意事项

  • 修改配置后先清空浏览器缓存,旧的307跳转记录会被浏览器强缓存,导致测试结果不准
  • POST表单的action地址写带.php后缀或者无后缀都可以正常传参,不需要修改现有业务代码
  • 如果后续新增静态资源,不需要调整规则,新增的三条资源存在判断会自动跳过静态资源的重写

内容的提问来源于stack exchange,提问作者Ayoub Mafkoud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:24:20