根本原因是WKWebView默认不发送Origin头导致CORS预检失败,且credentials支持依赖原生配置;需在创建前注入Cookie、显式设置Origin头(调试用)、避免强依赖Referer,并务必真机测试。

iOS WebView 中 HTML5 发起跨域请求失败,根本原因不是前端代码写错了,而是 WKWebView 默认禁用 CORS 预检(preflight)响应头的透传,且不自动携带 Cookie 或认证凭据——哪怕服务端已正确配置 Access-Control-Allow-Origin,也大概率 403 或直接被拦截。
WKWebView 默认不发送 Origin 头导致预检跳过
原生 iOS 的 WKWebView 在发起非简单请求(如带 Content-Type: application/json、自定义 header、POST + JSON body)时,**不会主动在预检请求中带上 Origin 头**,导致后端中间件(如 Nginx、Express CORS 插件)无法识别这是跨域请求,从而不返回 Access-Control-Allow-Origin 等响应头,浏览器最终拒绝主请求。
- 验证方式:用 Charles/Fiddler 抓包,看 OPTIONS 请求是否含
Origin;若无,即为此问题 - 临时绕过:前端改用
GET+ query 参数(简单请求),但不可用于登录、提交等场景 - 正解:在
WKWebView加载页面前,通过WKWebViewConfiguration启用allowsInlineMediaPlayback无效,真正要设的是websiteDataStore和自定义URLSchemeHandler拦截并重写请求头——但更轻量的做法是让前端发请求时显式加headers: { 'Origin': 'https://yourdomain.com' }(仅限调试,生产环境不推荐伪造)
fetch/fetch with credentials 在 WKWebView 中失效
fetch(url, { credentials: 'include' }) 在 iOS 14+ 上仍可能被忽略,因为 WKWebView 对 credentials 的支持依赖于 NSURLSessionConfiguration 级别的 cookie 策略,而非 JS 层控制。
- 现象:请求发出但没带 Cookie,后端鉴权失败,返回 401
- 关键点:必须在创建
WKWebView前,用HTTPCookieStorage.shared.setCookie(_:for:mainDocumentURL:)主动注入 Cookie,并确保后端Set-Cookie响应头含SameSite=None; Secure(iOS 要求 HTTPS + 显式声明) - 替代方案:改用
XMLHttpRequest并手动 setRequestHeader('Cookie', ...),但需先从HTTPCookieStorage同步读取最新值
iOS 15+ 引入的 strict-origin-when-cross-origin 影响 Referer
iOS 15 起,WKWebView 默认启用 strict-origin-when-cross-origin referrer 策略,导致某些依赖完整 Referer 的后端风控逻辑(如来源域名白名单校验)误判为非法请求。
立即学习“前端免费学习笔记(深入)”;
- 错误表现:后端日志里
Referer只剩协议+域名(如https://a.com),丢失 path 和 query - 修复方式:在 WebKit 配置中关闭该策略:
configuration.defaultWebpagePreferences.allowsContentJavaScript = true不相关;真正有效的是在WKWebView实例创建后,调用evaluateJavaScript("document.referrer")获取当前值,再通过 native bridge 透传给后端做兼容判断 - 更稳妥做法:后端不要强依赖
Referer做权限控制,改用 token 或签名参数
最易被忽略的一点:iOS 模拟器和真机行为不一致——模拟器默认允许部分跨域行为,而真机(尤其 iOS 16.4+)会严格执行 CORS 规范。务必在真机上测试,且开启 Web Inspector 查看 Console 里的具体 CORS 错误信息(如 “Blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header”),而不是只看 Network 面板里有没有响应。










