在前后端分离还不流行的年代,同一个 URL 往往既要服务浏览器的普通访问,又要服务页面里发出的异步请求。服务端需要知道请求的类型,才能决定返回完整 HTML 页面还是返回 JSON 数据,或者对非法请求直接拦截。判断一个 HTTP 请求是否为 AJAX 请求,最常用的依据就是请求头中的 X-Requested-With 字段,但它的原理和局限性很多人并不清楚。本文从请求头原理、各语言实现和安全性三个角度,把这个问题彻底讲透。

X-Requested-With 请求头的原理
AJAX 请求和普通 HTTP 请求在传输层面没有任何区别,它们都是标准的 HTTP 报文。所谓判断 AJAX 请求,本质上只能依赖一些约定俗成的特征,其中最通用的就是 X-Requested-With 这个自定义请求头。当它的值为 XMLHttpRequest 时,服务端通常就认定这是一个 AJAX 异步请求。
这个约定最早由 Prototype 框架引入,后来被 jQuery 等主流库沿用至今。jQuery 的 ajax 方法默认会在每个请求头中加上这一行:
$.ajax({
url: "/api/user",
type: "GET",
// setHeaders 里默认已包含 X-Requested-With: XMLHttpRequest
success: function (data) {
console.log(data);
}
});
发送原生 XMLHttpRequest 请求时,框架不会自动带这个头,需要手动设置。fetch API 同样如此,这也是很多开发者误以为原生请求不是 AJAX 的原因。正确写法如下:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/api/user");
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.send();
// fetch 写法
fetch("/api/user", {
headers: {
"X-Requested-With": "XMLHttpRequest"
}
});
需要注意,带自定义头的请求会触发跨域预检请求(OPTIONS),这是使用该方案时一个容易被忽视的副作用。
各语言服务端的判断实现
服务端拿到请求后,读取请求头并做比较即可。下面给出几种常见语言的实现方式,核心逻辑完全一致:判断 X-Requested-With 的值是否等于 XMLHttpRequest。
PHP 中框架一般会封装好方法,原生写法如下:
<?php
function isAjax()
{
return isset($_SERVER["HTTP_X_REQUESTED_WITH"])
&& strtolower($_SERVER["HTTP_X_REQUESTED_WITH"]) === "xmlhttprequest";
}
if (isAjax()) {
echo json_encode(["code" => 0, "data" => []]);
} else {
// 非 AJAX 请求,返回完整页面或拒绝访问
http_response_code(403);
exit("Forbidden");
}
Node.js 的 Express 框架提供了 req.xhr 属性,其内部实现同样是比对请求头:
app.get("/api/user", function (req, res) {
if (req.xhr) {
res.json({ code: 0, data: {} });
} else {
res.status(403).send("Forbidden");
}
});
Java Servlet 中需要自己读取请求头,建议统一忽略大小写:
public static boolean isAjax(HttpServletRequest request) {
String header = request.getHeader("X-Requested-With");
return "XMLHttpRequest".equalsIgnoreCase(header);
}
除了看请求头,还可以结合 Accept 头辅助判断。AJAX 请求通常期望 JSON 或 XML,Accept 头会包含 application/json 之类的值,而浏览器地址栏访问时 Accept 值以 text/html 开头。两种方式结合使用,判断会更可靠一些。
这种判断方式的局限与安全风险
必须明确一点:X-Requested-With 是一个普通的自定义请求头,客户端可以随意设置或删除。用 curl 模拟一个 AJAX 请求只需要一行命令:
curl -H "X-Requested-With: XMLHttpRequest" https://yourdomain.com/api/user
因此这种判断只能用来区分请求形式,绝不能当作身份认证或防刷手段。如果把它当作安全机制,攻击者可以轻易绕过。真正需要防护的接口,应该依靠登录态校验、Token 验证、签名机制和频率限制等手段。
另一个局限是并非所有前端代码都会带这个头。旧项目中手写的 XMLHttpRequest、某些第三方 SDK 发出的请求可能没有这个头,服务端如果只认它就会误判。更稳妥的做法是由团队约定统一的自定义头,比如 App-Client: web,并在封装请求函数时强制添加,从源头保证一致性。
总结一下:判断 AJAX 请求的可靠做法是检查 X-Requested-With 头,必要时结合 Accept 头交叉验证;同时在架构上尽量让接口与页面路由分离,一个接口只返回一种格式,这样对请求来源的判断就从安全依赖退化成了锦上添花的辅助手段,系统整体也会更加清晰健壮。
AJAX请求判断X-Requested-WithHTTP请求头修改时间:2026-09-14 21:34:30