一个用户脚本试图访问跨源资源

 人参与 | 时间:2026-10-17 07:06:19
```html

Tampermonkey 弹出一个红色警告框:@grant none 的个用脚本试图用 fetch 请求另一个域名,浏览器直接掐断了连接。户脚这不是本试 bug,是图访浏览器在替你挡子弹。

很多人写用户脚本时习惯性把 @grant 写成 none,问跨然后发现跨域请求全挂了。源资源原因不复杂:@grant none 意味着脚本运行在页面的个用 JavaScript 上下文里,它继承的户脚是页面的源。你在 example.com 上跑脚本,本试脚本就只能老老实实请求 example.com 的图访资源。想请求 api.another.com?问跨浏览器说不行。

这是源资源同源策略在起作用。同源策略从 Netscape 时代就存在,个用核心逻辑就一句话:不同源的户脚文档和脚本之间不能随意读取对方的数据。源由协议、本试域名、端口三者共同决定,任何一个不同就算跨源。你从 https://a.com 发请求到 https://b.com,哪怕两个域名指向同一台服务器,浏览器照样拦截。

那为什么有些用户脚本能跨域?因为它们用了 @grant GM_xmlhttpRequest。这个 API 不走页面的 XMLHttpRequest,而是由 Tampermonkey 扩展本身发起请求。扩展运行在浏览器的特权环境里,不受页面同源策略约束。Tampermonkey 拿到数据后再传给脚本。权限层级不一样,能做的事自然不一样。

我见过一个典型的翻车案例。有人写了个脚本,想从豆瓣抓取书籍评分显示在京东页面上。脚本里直接写了 fetch('https://book.douban.com/...'),本地测试没问题——因为他当时在豆瓣页面上调试。换到京东页面,请求全部被 CORS 拦截。控制台里一片红色报错,他以为是豆瓣封了 IP。折腾半天才反应过来:问题出在京东页面的源上。

CORS 是另一层机制。就算你用了 GM_xmlhttpRequest,目标服务器如果没返回正确的 Access-Control-Allow-Origin 头,某些情况下照样拿不到数据。不过 Tampermonkey 的 GM_xmlhttpRequest 通常能绕过 CORS 限制,因为它是从扩展的 background 页面发出的请求,浏览器对扩展的跨域请求有单独的权限模型。

这里有个容易混淆的点:@connect 指令。Tampermonkey 要求你在脚本头部声明允许访问的域名,比如 // @connect api.github.com。不写的话,GM_xmlhttpRequest 会弹窗询问用户是否允许。这是安全机制,防止脚本偷偷把你的数据发到未知服务器。很多人第一次遇到弹窗时一脸懵,以为脚本坏了。

说实话,跨源限制有时候确实烦人。但从安全角度看,它拦住了大量潜在的 CSRF 攻击和数据泄露。想象一下,如果没有同源策略,你在银行页面登录后,随便打开一个恶意网站,那个网站的脚本就能直接读取你银行页面的 DOM,拿到余额、转账记录,甚至发起转账请求。同源策略是浏览器安全模型的基石之一,不是随便能绕过的。

写用户脚本的人迟早会撞上这堵墙。理解它比抱怨它有用。该用 GM_xmlhttpRequest 就用,该声明 @connect 就声明。别跟浏览器的安全模型较劲,你赢不了。

``` 顶: 5839踩: 28