通过Accept Header区分AJAX与浏览器请求的策略是否可靠?
问题:区分AJAX与浏览器请求的Accept Header策略是否可靠?
我需要区分浏览器常规请求(比如HTML表单提交)和AJAX请求,目前观察到:
- 常规HTML表单提交的请求头
Accept值为:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 - 我自己写的AJAX请求(使用
fetch)的Accept头明确设置为:application/json
对应的AJAX代码:
fetch("/auth/login", { method: "POST", headers: { "Accept": "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ email: emailInput.value, pword: pwordInput.value, }), });
基于这个差异,我在服务器端做了如下校验:
if (!req.headers.accept.includes("application/json")) { req.flash("loginError", "Please enable JavaScript or use a browser that supports JavaScript to continue."); return res.redirect("/auth/login"); }
现在有三个疑问:
- 这个策略在所有浏览器及版本中区分AJAX和浏览器请求是否可靠?
- 所有浏览器的常规请求
Accept头格式是否一致? - 会不会存在浏览器常规请求也包含
application/json,导致校验失效的情况?
结论:这个策略不可靠,存在多种失效场景
1. 浏览器常规请求的Accept头没有统一格式
不同浏览器、同一浏览器的不同版本,常规请求的Accept头都会有差异。比如旧版Chrome和Firefox的Accept头会有不同的图片格式优先级,部分浏览器在特定场景下(比如页面加载过JSON资源),表单提交的Accept头可能会带上application/json。另外,浏览器扩展也可能修改请求头,让常规请求的Accept字段包含该值。
2. 确实存在常规请求包含application/json的情况
- 安装了调试类、API相关的浏览器扩展时,这类工具可能会自动给所有请求的Accept头添加
application/json; - 部分浏览器处理混合了HTML和JSON内容的页面时,表单提交的Accept头也可能包含
application/json; - 用户可以通过开发者工具手动修改请求头,让常规表单请求带上该字段,直接绕过你的校验。
3. 更可靠的区分方案
如果要准确区分AJAX和常规浏览器请求,推荐以下几种方式:
- 自定义请求头:在AJAX请求中添加一个自定义头,比如
X-Requested-With: XMLHttpRequest(这是jQuery等框架的传统做法),服务器端校验这个头是否存在; - 通过Content-Type区分:AJAX请求你已经设置了
Content-Type: application/json,而常规表单提交的Content-Type是application/x-www-form-urlencoded或multipart/form-data,可以通过校验这个字段来区分; - 分离路由:把AJAX请求和常规表单请求的路由分开,比如AJAX用
/api/auth/login,常规表单用/auth/login,从根源上区分两种请求。
内容的提问来源于stack exchange,提问作者Oscar
相关产品推荐
相关产品推荐

