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

Apache Mod Rewrite异常:POST请求先被301转为GET再执行307重写导致POST数据丢失API失效

Apache Mod Rewrite导致POST请求被转为GET的排查与解决

最近遇到了一个头疼的Apache Mod Rewrite问题:所有POST请求在执行我自定义的重写规则前,居然被自动转成了GET请求,导致POST数据丢失,API直接罢工,连iOS客户端都崩溃了。折腾了两天才找到根源,分享出来给大家避避坑。

问题现象

我通过POST请求调用API地址:https://s1.****.com//I2amZMjAK6q8nmkuBY3TEK1jkqgZyQ4S/1.3/getclientid,结果发现POST数据完全丢失,API返回错误。查看服务器日志后发现,请求先被301重定向成了GET,之后才执行我配置的307重写规则,最终导致整个流程异常。

当前使用的.htaccess配置

我的.htaccess文件内容如下:

RewriteEngine On
RewriteBase /
RewriteCond %{ENV:REDIRECT_END} =1
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule "^/?([\w]+)/([0-9\.]+)/assets/(.*)" "/assets/$1/$3" [L,E=END:1]
RewriteRule ^verifycode/([a-zA-Z0-9_-]+)/?$ vercode.php?code=$1 [L]
RewriteRule "^/?([\w]+)/([0-9\.]+)/(.*)$" "/clients/jsonrest.php/$1/$2/$3" [R=307]

日志分析

我开启了LogLevel alert rewrite:trace8查看重写日志,发现自定义的Rewrite规则匹配完全正常,但查看access.log时,记录却暴露了问题:

*.*.119.49 - - [09/Sep/2021:07:03:53 +0000] "POST /I2amZMjAK6q8nmkuBY3TEK1jkqgZyQ4S/1.3/getclientid HTTP/1.1" 301 283 "-" "BDSSport/1.06.07 (com.bizdev-strategy.container; build:2397; iOS 12.5.4) Alamofire/5.1.0"
*.*.119.49 - - [09/Sep/2021:07:03:54 +0000] "GET /I2amZMjAK6q8nmkuBY3TEK1jkqgZyQ4S/1.3/getclientid HTTP/1.1" 307 306 "-" "BDSSport/1.06.07 (com.bizdev-strategy.container; build:2397; iOS 12.5.4) Alamofire/5.1.0"
*.*.119.49 - - [09/Sep/2021:07:03:54 +0000] "GET /clients/jsonrest.php/I2amZMjAK6q8nmkuBY3TEK1jkqgZyQ4S/1.3/getclientid HTTP/1.1" 200 161 "-" "BDSSport/1.06.07 (com.bizdev-strategy.container; build:2397; iOS 12.5.4) Alamofire/5.1.0"

可以看到,最初的POST请求直接返回了301状态码,被客户端自动转为GET请求,之后才触发了我配置的307重定向,但此时POST数据已经丢失了。

排查过程

我花了整整一天多时间,反复排查重写日志、API代码和iOS客户端代码,甚至怀疑是Apache版本的问题(我的服务器用的是Apache/2.4.6,另一台测试服务器相同配置却完全正常)。最后才发现,问题居然出在HTTP转HTTPS的重定向配置上:iPhone应用里调用的是http://而非https://,而服务器上的HTTP转HTTPS重定向用了默认的301状态码,这会导致客户端自动将POST请求转为GET请求。

原因解释

Apache默认的HTTP转HTTPS重定向(比如用mod_alias的Redirect指令,或者未指定状态码的mod_rewrite规则)会返回301永久重定向,而根据HTTP规范,301重定向会让客户端将POST请求转为GET请求。这就导致我的自定义307重写规则(本来是保留POST方法的)完全没机会发挥作用,因为请求已经被提前转成GET了。

解决方法

把HTTP转HTTPS的重定向规则改成307临时重定向或者308永久重定向,这两个状态码都会保留原始请求方法(POST)。示例配置如下:

RewriteEngine On
# 检查是否为HTTPS请求
RewriteCond %{HTTPS} off
# 重定向到HTTPS,用307保留请求方法
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=307]

如果需要永久重定向(比如确定不再支持HTTP),可以把R=307改成R=308,同样会保留POST方法。

总结

这次问题完全是人为失误导致的:客户端调用了HTTP地址,而服务器的HTTP转HTTPS重定向配置不正确,用了会改变请求方法的301状态码。折腾了两天才找到根源,希望我的经历能帮大家节省时间——遇到POST被转GET的情况,先检查是否有HTTP/HTTPS之间的重定向,别像我一样绕了大弯!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:32:50