最准确方式是用$request->server('request_method')获取原始http方法,因它绕过_method伪造和中间件干扰;$request->method(true)在旧版tp6中存在bug,不可靠。

如何在 ThinkPHP 中准确获取当前请求的 HTTP 方法类型
ThinkPHP 提供了多种方式读取请求方法,但直接调用 $request->method() 并不总能反映客户端真实发送的 method —— 尤其在表单提交、AJAX 携带 _method 伪造或启用 method override 时,它默认返回“被伪造后”的方法(即模拟的 PUT/DELETE 等),而非原始 TCP 层的 POST 或 GET。
如果你要做请求统计(比如记录「真实发起的 method」用于审计、日志或限流),必须区分「原始 method」和「语义 method」:
-
$request->method(true):返回原始请求方法(绕过_method覆盖) -
$request->method(false)或$request->method():返回经过 method override 处理后的语义方法(默认行为) - 原始 method 只能从
$_SERVER['REQUEST_METHOD']或$request->server('REQUEST_METHOD')安全读取,且不受任何中间件干扰
在中间件中统计请求 method 的完整写法
最稳妥的统计点是全局中间件,避免控制器里漏统计或重复统计。以下是在 app/middleware/RequestStat.php 中的实现:
namespace app\middleware;
use think\Request;
use think\Response;
class RequestStat
{
public function handle(Request $request, \Closure $next): Response
{
// ✅ 获取原始请求方法(未被 _method 干扰)
$rawMethod = $request->server('REQUEST_METHOD', 'GET');
// ✅ 获取路由绑定的方法(可选:用于对比分析)
$action = $request->action() ?: 'unknown';
$controller = $request->controller() ?: 'unknown';
// ✅ 记录到日志(或写入 Redis/数据库)
\think\Log::record("METHOD:{$rawMethod} | CONTROLLER:{$controller} | ACTION:{$action}", 'stat');
return $next($request);
}
}
注意:$request->server('REQUEST_METHOD') 是最底层、最可靠的来源;$request->method(true) 在部分旧版 TP6(如 6.0.0~6.0.3)中存在 bug,可能仍受 _method 影响,所以优先用 server()。
统计 POST 请求但排除表单伪造场景的判断逻辑
很多业务需要单独统计「真实 POST」(如接口调用),而过滤掉由 HTML 表单通过 _method=PUT 伪装来的 POST。这时不能只看 $_SERVER['REQUEST_METHOD'] === 'POST',还要结合内容类型和参数判断:
- 真实 API POST 通常带
Content-Type: application/json,且无_method参数 - 伪造 PUT/DELETE 的表单 POST 必定含
_method字段(且值为PUT/DELETE) - 因此可组合判断:
$_SERVER['REQUEST_METHOD'] === 'POST' && !$request->has('_method', 'post')
示例代码片段:
$isRealPost = (
$request->server('REQUEST_METHOD') === 'POST'
&& !$request->has('_method', 'post')
&& !in_array(strtolower($request->header('content-type')), [
'application/x-www-form-urlencoded',
'multipart/form-data'
], true)
);
⚠️ 注意:multipart/form-data 也可能用于真实文件上传 POST,是否排除取决于你的统计目标 —— 如果只关心 JSON 接口,就保留该判断;如果要统计所有非伪造 POST,删掉 content-type 判断即可。
使用 Db 或 Cache 做轻量级实时计数时的注意事项
如果把 method 统计写入数据库或 Redis,别在每次请求都执行 INSERT,而是用原子操作聚合:
- Redis 推荐用
INCRBY stats:method:POST 1,高效且线程安全 - MySQL 若必须写表,建议按「日期 + method」分组,用
INSERT ... ON DUPLICATE KEY UPDATE count = count + 1避免并发冲突 - TP6 的
Db::execute()不支持原生命令中的变量插值,务必用参数绑定或拼接字符串(需手动转义) - 不要在中间件里做耗时操作(如网络请求、大事务),否则拖慢所有请求
一个安全的 Redis 计数示例:
$key = 'stats:method:' . strtoupper($request->server('REQUEST_METHOD'));
\think\Cache::store('redis')->inc($key);
Redis store 需已在 config/cache.php 中配置好,且 key 命名带前缀避免冲突。
真实请求 method 的判定边界比表面看起来更模糊 —— 比如某些 CDN 或反向代理会重写 REQUEST_METHOD,或者前端用 fetch 发送带 body 的 GET 请求(虽不符合规范但确实存在)。统计逻辑上线前,务必用 curl -X GET -d '{}' http://your.app/ 这类非常规请求验证原始 method 的捕获是否稳定。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











