# Service-Worker-Allowed 响应头

> Service-Worker-Allowed 设置 Service Worker 脚本可请求的最大路径 scope，可超出脚本所在目录。

`Service-Worker-Allowed` 是随 Service Worker 脚本返回的 HTTP 响应标头，用来设置注册可请求的最大路径 scope，让作用域可以超出脚本所在目录。

## 浏览器与平台支持

按照 Service Workers 规范，注册 Service Worker 需要安全上下文。

## 工作原理

响应不带这个标头时，Service Workers 规范根据脚本 URL 的目录得出最大允许 scope。因此，位于
`/product/sw.js` 的脚本默认以 `/product/` 为最大值。随脚本返回
`Service-Worker-Allowed: /` 后，注册可以请求 `/`。

标头的值是相对脚本 URL 解析的 URL。规范会比较请求的 scope 路径与该最大路径。请求的 scope
路径不以最大允许路径开头，或标头 URL 与脚本 URL 不同源，都会使注册任务以
`SecurityError` 拒绝。如果标头值无法解析为 URL，fetch 会以 network error 完成；随后更新算法
会以 `TypeError` 拒绝该任务，除非此前已调用 `SecurityError`。

:::security
Service Workers 规范说明，路径限制有助于在同一个源的不同目录托管不同用户内容的网站。规范
同时说明路径不是严格的安全边界；站点分区需要安全隔离时，使用不同的源。
:::

:::caution
当 `/product/sw.js` 在没有放宽响应头时请求 scope `/`，Chromium 的 `service_worker_loader_helpers.cc` 会拼出这句话（[Chromium 源码](https://github.com/chromium/chromium/blob/main/content/browser/service_worker/service_worker_loader_helpers.cc)）：
`The path of the provided scope ('/') is not under the max scope allowed ('/product/'). Adjust the scope, move the Service Worker script, or use the Service-Worker-Allowed HTTP header to allow the scope.`
:::

## 示例

服务器必须把标头附加到 Service Worker 脚本响应，而不是调用 `register()` 的页面。然后，
客户端才能请求对应的更宽 scope。

### 返回根路径最大 scope

此 Node HTTP 处理器随 `/product/sw.js` 返回该标头。Service Worker 正文是有效的 JavaScript，
安装时不会新增缓存条目。

```js
import { createServer } from 'node:http';

createServer((request, response) => {
  if (request.url === '/product/sw.js') {
    response.writeHead(200, {
      'content-type': 'text/javascript',
      'service-worker-allowed': '/',
    });
    response.end("self.addEventListener('install', () => {});");
    return;
  }

  response.writeHead(404);
  response.end('Not found');
}).listen(8080);
```

带有此响应时，规范允许 `/product/sw.js` 请求 `/` 作为注册 scope。

### 注册更宽 scope 并提供回退

注册前先检测是否支持 Service Worker。注册失败时，保留页面的在线功能并报告部署错误，不要假定 Worker 已经控制页面。

```js
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/product/sw.js', { scope: '/' })
    .then((registration) => {
      console.log('Registered scope:', registration.scope);
    })
    .catch((error) => {
      console.error('Service worker registration failed:', error);
      document.documentElement.dataset.offline = 'unavailable';
    });
} else {
  document.documentElement.dataset.offline = 'unsupported';
}
```

请求的 scope 必须位于标头指定的最大范围内。例如，`Service-Worker-Allowed: /product/`
不允许 `{ scope: '/' }`。

## 另请参阅

- [Service Worker 注册与 scope](/zh/reference/service-worker/registration-scope/)
- [Service Worker 生命周期](/zh/reference/service-worker/lifecycle/)
- [Service Worker 调试](/zh/reference/service-worker/debugging/)
- [Service Workers: Service-Worker-Allowed](https://w3c.github.io/ServiceWorker/#service-worker-allowed)（w3c.github.io）
- [Service-Worker-Allowed header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Service-Worker-Allowed)（MDN）