【问题标题】:Navigator.sendBeacon() to pass header informationNavigator.sendBeacon() 传递头信息
【发布时间】:2016-11-10 08:56:50
【问题描述】:

我使用navigator 与服务器通信,但问题是我们需要传递一些标头信息,因为有过滤器识别请求来自有效来源。

有人可以帮忙吗?

谢谢。

【问题讨论】:

  • @scotty-h 对此有何更新?我们是否允许设置自定义标头,尤其是“Auth”或“Authorization”,以允许将请求列入 REST API 的白名单?我认为 Chrome 和 Firefox 将在 2021 年中期删除 cors-safelist 警告。我们的目标是在 timeonsite tracker 中大量使用带有自定义 Auth 标头的 sendBeacon() 进行分析,这是至关重要的指标。

标签: javascript w3c


【解决方案1】:

首先,请注意并非所有浏览器都支持navigator.sendBeacon。在MDN documentation 上查看有关此功能以及当前支持的浏览器的更多详细信息。

您确实创建了一个 blob 来提供标头。这是一个例子:

window.onunload = function () {
  const body = {
    id,
    email,
  };
  const headers = {
    type: 'application/json',
  };
  const blob = new Blob([JSON.stringify(body)], headers);
  navigator.sendBeacon('url', blob);
});

navigator.sendBeacon 将发送一个 POST 请求,其中 Content-Type 请求标头设置为 headers.type 中的任何内容。不过,这似乎是您可以在信标中设置的唯一标头,根据W3C

sendBeacon 方法不提供自定义请求方法、提供自定义请求标头或更改请求和响应的其他处理属性的能力。需要对此类请求进行非默认设置的应用程序应使用 [FETCH] API 并将 keepalive 标志设置为 true。

我能够通过Chromium bug report 观察到它是如何工作的。

【讨论】:

  • 是的,您完全正确,因为这是docs 的实验性方法,仅适用于最新的浏览器,例如 chrome v39。
  • 如果我错了,请纠正我,但在 Chrome 中甚至还没有实现 keepalive for fetch 。 groups.google.com/a/chromium.org/forum/#!topic/loading-dev/…
  • 不幸的是,从 Chrome 59 开始,由于安全原因,这不再被允许,并且会抛出错误。请参阅:crbug.com/720283
  • @Scotty 这不适用于授权标头
【解决方案2】:

Processing Model of sendBeacon 中所写:

提取对象的字节流(transmittedData)和内容类型(contentType)。

提取的方式是described here

我收集到的是提取传输数据的内容类型,设置为HTTP请求的Content-Type。

1) 如果发送了 Blob 对象,则 Content-Type 成为 Blob 的类型。

2)如果发送了一个FormData对象,Content-Type就变成了multipart/form-data

3) 如果发送了 URLSearchParams 对象,则 Content-Type 变为 application/x-www-form-urlencoded

4) 如果发送的是普通字符串,则 Content-Type 变为 text/plain

实现不同对象的Javascript代码can be found here

【讨论】:

【解决方案3】:

如果您使用 Chrome 并尝试设置 content-type 标头,由于安全限制,您可能会遇到一些问题:

Uncaught DOMException: Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not any of the CORS-safelisted values for the Content-Type request header is disabled temporarily. See http://crbug.com/490015 for details.

sendBeacon API not working temporarily due to security issue, any workaround?

【讨论】:

    【解决方案4】:

    因为 sendBeacon(..) 方法不允许对标头进行操作,所以我将它们作为普通字段添加到表单中:

        const formData = new FormData();
        formData.append('authorization', myAuthService.getCachedToken());
        navigator.sendBeacon(myURL, formData);
    

    然后在主机端,我添加了一个简单的中间件类 (.Net),它捕获不带标头的 POST 请求并从正文中复制它们:

        public class AuthMiddleware
        {
            ...
            ...
            public async Task Invoke(HttpContext context)
            {
                string authHeader = context.Request.Headers["Authorization"];
                if (authHeader == null && context.Request.Method=="POST")
                {
                    context.Request.Headers["Authorization"] = string.Format("Bearer {0}",
                        context.Request.Form["authorization"].ToString());
                }
    
                await _next.Invoke(context);
            }
        }
    

    【讨论】:

    • 你需要在其他中间件之前添加中间件
    【解决方案5】:

    作为答案发布,因为我不允许在答案下发表评论:

    对于 Chrome,在 Chrome 版本 81 中修复了 navigator.sendBeacon 发送具有非 CORS 安全列表类型的 Blob 的问题,因此现在应该可以安全使用。 https://bugs.chromium.org/p/chromium/issues/detail?id=724929

    对于 IE,卸载事件中的替代方法是使用同步 ajax 请求,因为 IE 不支持 sendBeacon,但在我的情况下支持同步 ajax 调用。

    【讨论】:

      【解决方案6】:

      Chrome 39 后您无法使用 JSON 发送数据,出于安全考虑已被禁用。

      您可以尝试使用纯文本发送数据。但不要忘记从后端解析文本。

      【讨论】:

        【解决方案7】:

        在搜索了这个问题的答案后,我发现要通过导航器传递标头,我们需要传递一个 blob 对象。

        例如

        var headers = {type: 'application/json'};
        var blob = new Blob(request, headers);
        navigator.sendBeacon('url/to/send', blob);
        

        【讨论】:

        • 您的意思是要将new blob 大写成new Blob吗?
        • 还有什么是request?你能引用你的任何来源吗?
        • 我正在谈论的请求是在浏览器关闭时需要发送的票证数据列表以及安全标头,以便服务器可以将其识别为授权请求。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-03
        相关资源
        最近更新 更多