一、背景
前端需要对多有的get请求增加自定义的header头以满足业务场景的的需要,目前客户端前端有浏览器和小程序。
二、常见的get请求场景
- 静态资源src,如img、video等
- form表单get请求
- 打开新页面,如a标签、location.href
- XMLHttpRequest封装,如ajax,axios等
三、拦截方式
- 静态资源src,如img、video等 可以通过
Window.customElements自定义标签的方式。继承原有属性的基础上,使用CustomElementRegistry.define()进行扩展。以img标签为例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Proxy Image</title>
<script>
let requestImage = function (url, element) {
let request = new XMLHttpRequest();
request.responseType = 'blob';
request.open('get', url, true);
request.setRequestHeader('Authorization', '身份凭证');
request.onreadystatechange = e => {
if (request.readyState == XMLHttpRequest.DONE && request.status == 200) {
element.src = URL.createObjectURL(request.response);
element.onload = () => {
URL.revokeObjectURL(element.src);
}
}
};
request.send(null);
}
class AuthImg extends HTMLImageElement {
constructor() {
super();
this._lastUrl = '';
}
static get observedAttributes() {
return ['authSrc'];
}
connectedCallback() {
let url = this.getAttribute('authSrc');
if (url !== this._lastUrl) {
this._lastUrl = url;
requestImage(url, this);
}
console.log('connectedCallback() is called.');
}
}
window.customElements.define('auth-img', AuthImg, {extends: 'img'});
</script>
</head>
<body>
<img width="100" height="100" is="auth-img"
authSrc="http://threex.top/images/image_201909111450326.jpg">
</body>
</html>
-
针对form表单get请求,原生的form表单无法实现,需要xhr模拟提交。一般业务上通过组件库,使用xhr进行提交,可暂不考虑
-
打开新页面,如a标签、location.href,通过
chrome插件可以实现,无法在业务上使用。 -
XMLHttpRequest封装,如ajax,axios等。
vue + axios项目中 业务上通常在axios.interceptors拦截中作统一的请求头处理。
axios.interceptors.request.use((config) => { const authStore = useAuthStore(); config.headers['Authorization'] = '身份凭证'; return config; });也可以对XMLHttpRequest原型send方法进行处理
let req = XMLHttpRequest; (function(open, send) { XMLHttpRequest.prototype.open = function() { open.apply(this, arguments); } XMLHttpRequest.prototype.send = function () { this.setRequestHeader('Authorization', '身份凭证') send.apply(this, arguments); } })(req.prototype.open, XMLHttpRequest.prototype.send)
四、结论
目前浏览器尚且不能覆盖所有场景,小程序等应用端更是不支持。等架构师那边把思路打开,看下能不能另辟蹊径。