前端请求拦截模板:axios、XHR、axios + XHR 三种模式
在前端调试、联调、逆向分析、灰度验证时,经常会遇到这样的需求:
- 某个接口请求发出去前,想临时改 URL 参数
- 某个请求想强行追加
Authorization
- 某个 POST 请求想修改请求体里的字段
- 不改源码,只想在浏览器里临时“劫持”某条请求
这篇文章整理 3 套可直接复用的模板:
axios 拦截
XHR 拦截
axios + XHR 双保险拦截
适用场景:
- Chrome 控制台临时注入
- 本地调试
- 前端页面请求改写
- 后续博客或项目里直接套模板
先搞清楚:你到底要改什么
请求拦截一般分 3 类:
改 URL 查询参数
例如原请求:
1
| http://localhost:1024/prod-api/system/user/getUserList
|
改成:
1
| http://localhost:1024/prod-api/system/user/getUserList?deptId=10001
|
- 如果原 URL 没有参数,用 ?
- 如果原 URL 已经有参数,再追加时用 &
正确示例:
1 2 3
| ...getUserList?deptId=10001
...getUserList?deptId=10001&status=1
|
例如追加:
1
| Authorization: xxxxxxxxx
|
改请求体 Body
常见于 POST/PUT 请求,比如原 body:
1 2 3 4
| { "pageNum": 1, "pageSize": 10 }
|
改成:
1 2 3 4 5
| { "pageNum": 1, "pageSize": 10, "deptId": 10001 }
|
使用前先判断请求类型
在 Chrome 打开开发者工具:
重点看这几个字段:
Request Method
Request URL
Query String Parameters
Request Payload
Initiator
判断规则:
如果项目是 axios
一般可在源码中直接用 axios.interceptors.request.use(...)
如果页面里是 XMLHttpRequest
一般控制台直接重写 XMLHttpRequest.prototype.open/send
如果你不确定 axios 底层会不会绕过你的逻辑
那就上 axios + XHR 双拦截
axios 拦截模板
适用于:
- 项目源码中直接接入
- Vue / React / 后台管理系统
- 已明确页面请求由 axios 发起
模板 1:axios 拦截 GET 请求,自动追加 URL 参数
1 2 3 4 5 6 7 8 9 10 11
| import axios from 'axios'
axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.params = { ...(config.params || {}), deptId: 10001 } } return config })
|
这段代码会把:
1
| /prod-api/system/user/getUserList
|
自动改成:
1
| /prod-api/system/user/getUserList?deptId=10001
|
模板 2:axios 拦截并追加 Authorization
1 2 3 4 5 6 7 8 9 10 11
| import axios from 'axios'
axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.headers = { ...(config.headers || {}), Authorization: 'Bearer 你的token' } } return config })
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import axios from 'axios'
axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.params = { ...(config.params || {}), deptId: 10001 }
config.headers = { ...(config.headers || {}), Authorization: 'Bearer 你的token' } }
return config })
|
模板 4:axios 改 POST 请求 body
如果请求是 JSON body:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import axios from 'axios'
axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { if (config.data && typeof config.data === 'string') { try { const data = JSON.parse(config.data) data.deptId = 10001 config.data = JSON.stringify(data) } catch (e) { console.log('data 不是 JSON 字符串,未处理') } } else if (config.data && typeof config.data === 'object') { config.data = { ...config.data, deptId: 10001 } } } return config })
|
XHR 拦截模板
适用于:
- 在 Chrome 控制台临时注入
- 老项目
- axios 底层走 XHR
- 不改源码,只想临时调试
模板 1:XHR 拦截 GET 请求并追加 URL 参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| (() => { const TARGET = '/prod-api/system/user/getUserList' const DEPT_ID = '10001'
const oldOpen = XMLHttpRequest.prototype.open XMLHttpRequest.prototype.open = function (method, url, async, user, password) { if (typeof url === 'string' && url.includes(TARGET)) { const u = new URL(url, location.origin) u.searchParams.set('deptId', DEPT_ID) url = u.toString() console.log('[XHR已改写URL]', url) } return oldOpen.call(this, method, url, async, user, password) } console.log('XHR URL 拦截器已生效') })()
|
模板 2:XHR 拦截并追加 Authorization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| (() => { const TARGET = '/prod-api/system/user/getUserList' const TOKEN = '你的token,不要带 Bearer 前缀'
const oldOpen = XMLHttpRequest.prototype.open const oldSend = XMLHttpRequest.prototype.send const oldSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { this._matchTarget = false if (typeof url === 'string' && url.includes(TARGET)) { this._matchTarget = true } return oldOpen.call(this, method, url, async, user, password) }
XMLHttpRequest.prototype.setRequestHeader = function (name, value) { return oldSetRequestHeader.call(this, name, value) }
XMLHttpRequest.prototype.send = function (body) { if (this._matchTarget) { oldSetRequestHeader.call(this, 'Authorization', `Bearer ${TOKEN}`) console.log('[XHR已注入Authorization]') } return oldSend.call(this, body) } console.log('XHR Header 拦截器已生效') })()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| (() => { const TARGET = '/prod-api/system/user/getUserList' const DEPT_ID = '10001' const TOKEN = '你的token'
const oldOpen = XMLHttpRequest.prototype.open const oldSend = XMLHttpRequest.prototype.send const oldSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { this._matchTarget = false if (typeof url === 'string' && url.includes(TARGET)) { const u = new URL(url, location.origin) u.searchParams.set('deptId', DEPT_ID) url = u.toString() this._matchTarget = true console.log('[XHR已改写URL]', url) } return oldOpen.call(this, method, url, async, user, password) }
XMLHttpRequest.prototype.setRequestHeader = function (name, value) { return oldSetRequestHeader.call(this, name, value) }
XMLHttpRequest.prototype.send = function (body) { if (this._matchTarget) { oldSetRequestHeader.call(this, 'Authorization', `Bearer ${TOKEN}`) console.log('[XHR已注入Authorization]') } return oldSend.call(this, body) } console.log('XHR URL + Header 拦截器已生效') })()
|
模板 4:XHR 改 POST Body
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| (() => { const TARGET = '/prod-api/system/user/getUserList'
const oldOpen = XMLHttpRequest.prototype.open const oldSend = XMLHttpRequest.prototype.send
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { this._matchTarget = typeof url === 'string' && url.includes(TARGET) return oldOpen.call(this, method, url, async, user, password) } XMLHttpRequest.prototype.send = function (body) { if (this._matchTarget && typeof body === 'string') { try { const data = JSON.parse(body) data.deptId = 10001 body = JSON.stringify(data) console.log('[XHR已改写Body]', body) } catch (e) { console.log('[XHR] body 不是 JSON,未处理') } } return oldSend.call(this, body) } console.log('XHR Body 拦截器已生效') })()
|
axios + XHR 双保险模板
适用于:
- 不确定请求到底是 axios 还是原生 XHR
- 页面逻辑复杂
- 既想在源码层拦,也想在浏览器层兜底
- 联调时追求稳定命中
模板 1:axios + XHR 同时追加 URL 参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| if (window.axios) { window.axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.params = { ...(config.params || {}), deptId: 10001 } console.log('[axios已改写params]', config.url) } return config }) }
(() => { const TARGET = '/prod-api/system/user/getUserList' const DEPT_ID = '10001' const oldOpen = XMLHttpRequest.prototype.open
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { if (typeof url === 'string' && url.includes(TARGET)) { const u = new URL(url, location.origin) u.searchParams.set('deptId', DEPT_ID) url = u.toString() console.log('[XHR已改写URL]', url) } return oldOpen.call(this, method, url, async, user, password) } console.log('axios + XHR URL 双拦截已生效') })()
|
模板 2:axios + XHR 同时追加 Authorization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| if (window.axios) { window.axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.headers = { ...(config.headers || {}), Authorization: '你的token' } console.log('[axios已注入Authorization]', config.url) } return config }) }
(() => { const TARGET = '/prod-api/system/user/getUserList' const TOKEN = '你的token'
const oldOpen = XMLHttpRequest.prototype.open const oldSend = XMLHttpRequest.prototype.send const oldSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { this._matchTarget = typeof url === 'string' && url.includes(TARGET) return oldOpen.call(this, method, url, async, user, password) }
XMLHttpRequest.prototype.setRequestHeader = function (name, value) { return oldSetRequestHeader.call(this, name, value) }
XMLHttpRequest.prototype.send = function (body) { if (this._matchTarget) { oldSetRequestHeader.call(this, 'Authorization', `${TOKEN}`) console.log('[XHR已注入Authorization]') } return oldSend.call(this, body) } console.log('axios + XHR Header 双拦截已生效') })()
|
模板 3:axios + XHR 全量模板(URL + Header + Body)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| if (window.axios) { window.axios.interceptors.request.use(config => { if (config.url && config.url.includes('/prod-api/system/user/getUserList')) { config.params = { ...(config.params || {}), deptId: 10001 } config.headers = { ...(config.headers || {}), Authorization: '你的token' } if (config.data && typeof config.data === 'string') { try { const data = JSON.parse(config.data) data.deptId = 10001 config.data = JSON.stringify(data) } catch (e) {} } else if (config.data && typeof config.data === 'object') { config.data = { ...config.data, deptId: 10001 } } console.log('[axios已拦截]', config.url) }
return config }) }
(() => { const TARGET = '/prod-api/system/user/getUserList' const DEPT_ID = '10001' const TOKEN = '你的token'
const oldOpen = XMLHttpRequest.prototype.open const oldSend = XMLHttpRequest.prototype.send const oldSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader
XMLHttpRequest.prototype.open = function (method, url, async, user, password) { this._matchTarget = false if (typeof url === 'string' && url.includes(TARGET)) { const u = new URL(url, location.origin) u.searchParams.set('deptId', DEPT_ID) url = u.toString() this._matchTarget = true console.log('[XHR已改写URL]', url) } return oldOpen.call(this, method, url, async, user, password) }
XMLHttpRequest.prototype.setRequestHeader = function (name, value) { return oldSetRequestHeader.call(this, name, value) }
XMLHttpRequest.prototype.send = function (body) { if (this._matchTarget) { oldSetRequestHeader.call(this, 'Authorization', `${TOKEN}`) if (typeof body === 'string') { try { const data = JSON.parse(body) data.deptId = 10001 body = JSON.stringify(data) console.log('[XHR已改写Body]', body) } catch (e) {} } console.log('[XHR已注入Authorization]') } return oldSend.call(this, body) } console.log('axios + XHR 全量双拦截已生效') })()
|
推荐的通用可复用模板
如果你后面要经常套用,建议把参数抽出来。
1 2 3
| const TARGET = '/prod-api/system/user/getUserList' const DEPT_ID = '10001' const TOKEN = '你的token'
|
以后只改这三个变量:
TARGET:目标接口
DEPT_ID:要注入的参数
TOKEN:要注入的 token
Chrome 控制台注入步骤
方式 1:临时调试
- 打开页面
- 按 F12
- 切到
Console
- 粘贴拦截脚本
- 回页面重新触发请求
方式 2:Sources -> Snippets 持久复用
如果你经常要用,可以把脚本存成 Snippet,这样比每次复制粘贴更方便。
- 打开 Chrome DevTools
- 进入
Sources
- 找到
Snippets
- 新建一个脚本
- 保存这套模板
- 以后右键直接运行
常见问题
为什么脚本执行了,但请求没改掉?
常见原因:
为什么 URL 追加参数后接口还是没生效?
可能是后端根本不认这个参数。例如:后端可能不是从 @RequestParam("deptId") 取值,而是从这里面取部门信息,这时你前端加了 deptId 也没用。
- 登录用户信息
- token
- session
- 请求头
- 网关上下文
axios 拦截和 XHR 拦截该选哪个?
选 axios
适合项目源码里改,最规范。
选 XHR
适合浏览器临时调试,最快。
选 axios + XHR
适合你不确定页面请求路径、想提高命中率。
结论
如果你只是临时调试,优先用:
XHR 拦截模板
如果你要在项目里长期使用,优先用:
axios 拦截模板
如果你不确定页面底层实现,或者想双保险,直接用:
axios + XHR 模板
后续复用时,只需要替换这几个值,即可快速套用。1 2 3
| const TARGET = '你的目标接口' const DEPT_ID = '你的参数值' const TOKEN = '你的token'
|