移动体验 / 方法解读

移动端 fetch 跨域请求为何报错 invalid token in CORS header

浏览器控制台显示 invalid token 'xyz' in CORS header 错误时,通常意味着服务器返回的 Access-Control-Allow-Methods 或 Access-Control-Allow-Headers 中包含非法字符。

检查服务器响应头中的非法字符

当移动端网页发起跨域请求时,浏览器会先发送 OPTIONS 预检请求。如果服务器返回的 Access-Control-Allow-Methods 或 Access-Control-Allow-Headers 响应头中包含非标准 HTTP 方法名或非 CORS 列表允许的头部名称,浏览器就会报错 invalid token 'xyz' in CORS header。例如,如果 Access-Control-Allow-Methods 包含了 'GET'、'POST' 以及非法的 'DELETE',或者 Access-Control-Allow-Headers 包含了 'Content-Type' 但同时也包含了 'X-Custom-Header',而该头部未被服务器明确允许,就会触发此错误。排查时需在服务器端检查这些响应头的具体值,确保只包含浏览器允许的 HTTP 方法和 CORS 安全列表中的头部名称。

在移动端调试时,可以通过开发者工具的 Network 面板查看预检请求的响应内容。重点检查响应头中的 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 字段。如果发现其中包含空格、特殊符号或未被 RFC 标准定义的方法名,必须立即修正。服务器端配置通常位于 Web 服务器(如 Nginx 或 Apache)的配置文件或后端框架的 CORS 中间件中。确保这些响应头只包含有效的 HTTP 方法(如 GET, POST, PUT, DELETE 等)和标准的请求头名称(如 Content-Type, Authorization 等),避免手动拼接字符串时引入非法字符。

确认请求方法与头部是否符合 CORS 规范

浏览器在发送跨域请求前,会根据请求的具体参数决定是否触发预检。如果请求使用了 GET、HEAD 或 POST 方法,且 Content-Type 仅限于 application/x-www-form-urlencoded、multipart/form-data 或 text/plain,则属于简单请求,不会触发预检。但如果请求使用了其他方法(如 PUT、DELETE)或自定义了非 CORS 安全列表的请求头,浏览器就会发送 OPTIONS 预检请求。此时,服务器必须在 Access-Control-Allow-Methods 中明确列出允许的方法,并在 Access-Control-Allow-Headers 中列出允许的自定义头部。如果请求中使用了服务器未列出的方法或头部,就会导致 invalid token 错误。

为了复现和验证问题,可以在移动端网页代码中临时修改请求参数。例如,将请求方法改为 POST,并在请求头中添加一个自定义头部(如 X-Test-Header)。然后观察浏览器控制台是否出现 invalid token 错误。如果错误消失,说明问题出在服务器对预检请求的响应配置上。此时需要确保服务器在响应 OPTIONS 请求时,正确返回了 Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 响应头,并且这些响应头中包含了请求中使用的所有方法和头部名称。

使用 no-cors 模式规避预检请求限制

如果服务器无法修改响应头配置,或者只需要发送埋点数据而不需要读取响应内容,可以在客户端使用 fetch 的 no-cors 模式来规避预检请求。当设置 mode 为 no-cors 时,浏览器会发送跨域请求,但不会检查 CORS 响应头,也不会读取响应内容。此时,响应将变为 opaque(不透明),其状态为 0,头部为空,且无法被 JavaScript 读取。这种方法适用于发送分析信标或通过 Service Worker 缓存资源等场景,但无法获取服务器返回的数据。

在移动端代码中,可以通过以下方式使用 no-cors 模式:fetch('https://api.example.com/log', { method: 'POST', mode: 'no-cors', body: data, });。需要注意的是,使用 no-cors 模式后,虽然请求会发送成功,但无法判断服务器是否真正处理了请求,也无法读取响应结果。因此,这种方法仅适用于不需要读取响应内容的场景。如果业务逻辑需要读取服务器返回的数据,则必须解决服务器端的 CORS 配置问题,确保响应头中包含正确的 Access-Control-Allow-Origin 等信息。

通过代理服务器转发请求解决跨域问题

如果无法控制远程服务器的 CORS 配置,可以使用代理服务器来转发请求。代理服务器位于用户和远程服务器之间,用户向代理服务器发送请求,代理服务器再向远程服务器转发请求,并将远程服务器的响应返回给用户。由于代理服务器和用户位于同一域名下,因此不会触发跨域限制。代理服务器可以在转发请求时,自动添加或修改 CORS 响应头,从而解决跨域问题。这种方法会增加请求的延迟,并引入对代理服务器的依赖,但在无法修改远程服务器配置时是一种有效的解决方案。

在移动端实现代理转发时,可以在后端部署一个代理服务,该服务负责接收前端请求,然后使用后端语言(如 Node.js、Python 等)的 HTTP 客户端向远程服务器发起请求。代理服务在获取远程服务器的响应后,需要添加 Access-Control-Allow-Origin 等响应头,然后返回给前端。前端代码中,只需将请求的目标地址改为代理服务器的地址即可。例如,前端请求 https://proxy.example.com/api/data,代理服务器再将该请求转发到 https://remote-api.example.com/data,并返回响应。

资料与延伸阅读

你可以通过以下原始资料核对文中概念,并继续深入阅读。

  1. CORS errors - HTTP | MDN ↗
← 更多移动体验文章返回顶部 ↑