[英]How to control the XMLHttpRequest object on an HTML5 Web Worker?
I have a page which will normally overrides window.XMLHttpRequest with a wrapper that does a few extra things like inserting in headers on certain requests. 我有一个页面通常会覆盖window.XMLHttpRequest一个包装器,它会做一些额外的事情,比如在某些请求中插入标题。
I have some functionality in a 3rd party library that uses HTML5 Worker, and we are seeing that this request does not use the XMLHttpRequest wrapper object. 我在使用HTML5 Worker的第三方库中有一些功能,我们发现此请求不使用XMLHttpRequest包装器对象。 So any request that this library makes is missing the required headers, and so the request will fail. 因此,此库所做的任何请求都缺少必需的标头,因此请求将失败。
Is there a way to control the XMLHttpRequest that any Worker the current thread creates? 有没有办法控制当前线程创建的任何工作者的XMLHttpRequest?
This 3rd party library code looks like this: 此第三方库代码如下所示:
function createWorker(url) {
var worker = new Worker(url);
worker.onmessage = function (e) {
if (e.data.status) {
onprogress(e.data.status);
} else if (e.data.error) {
onerror(e.data.error);
} else {
exportUtils.saveFile(new Blob([e.data]), params.fileName);
onfinish();
}
};
worker.postMessage(params); // window.location.origin +
return worker;
}
The Javascript that is returned by the URL variable above contains code like this: 上面的URL变量返回的Javascript包含如下代码:
return new Promise(function(t, r) {
var n = new XMLHttpRequest
, a = "batch_" + o()
, u = e.dataUrl.split(e.serviceUrl)[1]
, c = [];
n.onload = function() {
for (var e = this.responseText, n = this.responseText.split("\r\n"), o = 0, a = n.length, i = a - 1; o < a && "{" !== n[o].slice(0, 1); )
o++;
for (; i > 0 && "}" !== n[i].slice(-1); )
i--;
n = n.slice(o, i + 1),
e = n.join("\r\n");
try {
var u = JSON.parse(e);
t(u)
} catch (t) {
r(s + e)
}
}
,
n.onerror = function() {
r(i)
}
,
n.onabort = function() {
r(i)
}
,
n.open("POST", e.serviceUrl + "$batch", !0),
n.setRequestHeader("Accept", "multipart/mixed"),
n.setRequestHeader("Content-Type", "multipart/mixed;boundary=" + a);
for (var p in e.headers)
"accept" != p.toLowerCase() && n.setRequestHeader(p, e.headers[p]);
c.push("--" + a),
c.push("Content-Type: application/http"),
c.push("Content-Transfer-Encoding: binary"),
c.push(""),
c.push("GET " + u + " HTTP/1.1");
for (var p in e.headers)
c.push(p + ":" + e.headers[p]);
c.push(""),
c.push(""),
c.push("--" + a + "--"),
c.push(""),
c = c.join("\r\n"),
n.send(c)
}
)
The answer is both a soft "no" and an eventual "yes". 答案既是柔和的“不”,也是最终的“是”。
When a piece of code runs in a different context (like a webworker or an iframe), you do not have direct control of its global object (1). 当一段代码在不同的上下文(如webworker或iframe)中运行时,您无法直接控制其全局对象(1)。
What's more, XMLHttpRequest isn't the only way to send out network requests - you have several other methods, chief among them the fetch
api . 更重要的是,XMLHttpRequest并不是发送网络请求的唯一方法 - 你还有其他几种方法,其中主要是fetch
api 。
However, there's a relatively new kid in block called Service Workers which can help you quite a bit! 然而,有一个相对较新的孩子叫做服务工作者,它可以帮助你很多!
Service workers (abbrev. SWs) are very much like the web workers you already know, but instead of only running in the current page, they continue to run in the background as long as your user stays in your domain. 服务工作者 (缩写为SW)与您已经知道的Web工作人员非常相似,但只要您的用户留在您的域中,他们就会继续在后台运行,而不是仅在当前页面中运行。 They are also global to your entire domain , so any request made from your site will be passed through them. 它们对您的整个域也是全球性的 ,因此从您的站点发出的任何请求都将通过它们传递。
Their main purpose in life is reacting to network requests, usually used for caching purposes and offline content, serving push notifications, and several other niche uses. 它们的主要目的是响应网络请求,通常用于缓存和离线内容,提供推送通知,以及其他一些小众用途。
Let's see a small example (note, run these from a local webserver): 让我们看一个小例子(注意,从本地网络服务器运行这些):
// index.html
<script>
navigator.serviceWorker.register('sw.js')
.then(console.log.bind(console, 'SW registered!'))
.catch(console.error.bind(console, 'Oh nose!'));
setInterval(() => {
fetch('/hello/');
}, 5000);
</script>
// sw.js
console.log('Hello from a friendly service worker');
addEventListener('fetch', event => {
console.log('fetch!', event);
})
Here we're registering a service worker and then requesting a page every 5 seconds. 在这里,我们注册一个服务工作者,然后每5秒请求一个页面。 In the service worker, we're simple logging each network event, which can be caught in the fetch
event. 在服务工作者中,我们可以简单地记录每个网络事件,这些事件可以在fetch
事件中捕获。
On first load, you should see the service worker being registered. 首次加载时,您应该看到正在注册的服务工作者。 SWs only begin intercepting requests from the first page after they were installed...so refresh the page to begin seeing the fetch
events being logged. SW构成才开始拦截从它们安装后的第一个页面请求......所以刷新页面,开始看到fetch
被记录的事件。 I advise you to play around with the event properties before reading on so things will be clearer. 我建议你在阅读之前尽量使用事件属性,这样事情会更加清晰。
Cool! 凉! We can see from poking around with the event in the console that event.request
is the Request
object our browser constructed. 我们可以通过在控制台中Request
事件来看到event.request
是我们的浏览器构造的Request
对象。 In an ideal world, we could access event.request.headers
and add our own headers! 在理想的世界中,我们可以访问event.request.headers
并添加我们自己的标题! Dreamy, isn't it!? 梦幻,不是吗??
Unfortunately, request/response headers are guarded and immutable . 不幸的是, 请求/响应头是有保护的和不可变的 。 Fortunately, we are a stubborn bunch and can simply re-construct the request: 幸运的是,我们是一个顽固的群体,可以简单地重新构建请求:
// sw.js
console.log('Hello from a friendly service worker');
addEventListener('fetch', event => {
console.log('fetch!', event);
// extract our request
const { request } = event;
// clone the current headers
const newHeaders = new Headers();
for (const [key, val] of request.headers) {
newHeaders.append(key, val);
}
// ...and add one of our own
newHeaders.append('Say-What', 'You heard me!');
// clone the request, but override the headers with our own
const superDuperReq = new Request(request, {
headers: newHeaders
});
// now instead of the original request, our new request will take precedence!
return fetch(superDuperReq);
});
This is a few different concepts at play so it's okay if it takes more than once to get. 这是一些不同的概念,所以如果它需要不止一次就可以。 Essentially though, we're creating a new request which will be sent in place of the original one, and setting a new header! 基本上,我们正在创建一个新请求,它将代替原始请求发送,并设置一个新标头! Hurray! 欢呼!
Now, to some of the downsides: 现在,一些缺点:
(1) You can access the global object of an iframe in the same origin as you, but getting your code to run first to modify the global object is tricky indeed. (1)你可以访问一个iframe的全局对象在同一产地如你,但让你的代码先运行修改全局对象是棘手的确实。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.