挂钩所有 Fetch Api AJAX 请求
Posted
技术标签:
【中文标题】挂钩所有 Fetch Api AJAX 请求【英文标题】:Hook all Fetch Api AJAX requests 【发布时间】:2017-11-27 11:08:15 【问题描述】:如何挂钩所有使用 Fetch Api 的 AJAX 请求?以前我们可以这样做来挂钩所有 XMLHttpRequest:
(function()
var origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function()
console.log('request started!');
this.addEventListener('load', function()
console.log('request completed!');
console.log(this.readyState); //will always be 4 (ajax is completed successfully)
console.log(this.responseText); //whatever the response was
);
origOpen.apply(this, arguments);
;
)();
或者更好的是,如果你想添加到上面的函数中,你将如何挂钩所有 Fetch Api 和所有 XMLHttpRequest AJAX 请求?
【问题讨论】:
这个运气好吗?规范中似乎没有任何内容。 【参考方案1】:由于 Promise 的性质,这很容易做到:
var taperFunction = response => response;
var originalFetch = fetch;
fetch = (input, init) => originalFetch(input, init)
.then(response => new Promise((resolve) =>
resolve(taperFunction(response));
));
还有一个更复杂(显式)的例子:
var originalFetch = fetch;
fetch = (input, init) =>
debugger; // do what ever you want with request or reject it immediately
return originalFetch(input, init).then(response =>
// it is not important to create new Promise in ctor, we can await existing one, then wrap result into new one
return new Promise((resolve) =>
response.clone() // we can invoke `json()` only once, but clone do the trick
.json()
.then(json =>
debugger; // do what ever you want with response, even `resolve(new Response(body, options));`
resolve(response);
);
);
);
;
【讨论】:
【参考方案2】:其实FetchApi是原生浏览器支持的,只有一个接口:fetch
。
构造函数返回一个Promise,当你想返回你的Promise重写fetch的构造函数时,你无法得到Request
、Response
。
下面的代码不好用。
(function()
var oldFectch = fetch;
fetch.consotructor = function()
return new Promise(resolve, reject)
// your hook code
;
;
)();
那么,这是否意味着我们不能挂钩所有 Fetch Api ? 不!
首先,感谢window.fetch polyfill。
那么,让我们做点什么(编辑fetch.js)然后摇滚吧。
(function(self)
'use strict';
// comment or delete the following code block
// if (self.fetch)
// return
//
var support =
searchParams: 'URLSearchParams' in self,
iterable: 'Symbol' in self && 'iterator' in Symbol,
// ...
最后,把每件事都做得更好!
self.fetch = function(input, init)
return new Promise(function(resolve, reject)
var request = new Request(input, init)
var xhr = new XMLHttpRequest()
// Here we go!
// Now we get the XMLHttpRequest Object
// Do what you want!
xhr.onload = function()
var options =
status: xhr.status,
statusText: xhr.statusText,
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
var body = 'response' in xhr ? xhr.response : xhr.responseText
resolve(new Response(body, options))
// ...
【讨论】:
【参考方案3】:使用async
和await
,很简单:
const oldFetch = window.fetch
window.fetch = async (input, options) =>
return await oldFetch(input, options)
一个例子:
const oldFetch = window.fetch
window.fetch = async (input, options) =>
// modify the request here
console.log(input)
let response = await oldFetch(input, options)
// modify the response
let content = await response.text()
content = 'goodbye!'
return new Response(content,
status: response.status,
statusText: response.statusText,
headers: response.headers
)
console.log(await (await fetch('/hello')).text())
【讨论】:
以上是关于挂钩所有 Fetch Api AJAX 请求的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 5 - jQuery AJAX 有效,Fetch API 无效
javascript ajax 调用通过仅使用 POST 方法的 fetch 调用:奇怪的行为是 post 后跟 get plus 再次请求所有资源?