开启sendfile后iOS Safari等浏览器加载字体时CORS失败,因sendfile内核态零拷贝绕过用户态,导致add_header无法注入Access-Control-Allow-Origin头;应针对字体location禁用sendfile并显式添加CORS头。

开启 sendfile 后部分移动端浏览器(尤其是 iOS Safari 和某些 Android WebView)加载字体(如 .woff2、.ttf)时出现跨域失败(CORS 错误),根本原因在于 sendfile 绕过了用户态,导致 Nginx 无法在响应中正确注入 Access-Control-Allow-Origin 等 CORS 头 —— 即使你已在配置中显式添加了这些头。
为什么 sendfile 会导致 CORS 头丢失
sendfile 是内核态零拷贝机制:Nginx 直接让内核将文件从磁盘 fd 发送到 socket fd,不经过用户空间缓冲区。而 add_header、headers_more 等指令依赖于用户态响应构建阶段,此时响应头已“冻结”,后续无法动态追加。字体文件常被静态服务直接返回(location ~ \.(woff2|ttf|eot|svg)$),一旦匹配到 sendfile on,CORS 头就彻底失效。
验证是否是 sendfile 导致的问题
- 临时关闭 sendfile:
sendfile off;,重启 Nginx,用 iOS Safari 重新加载页面,观察字体是否正常加载且 Network 面板中响应头包含Access-Control-Allow-Origin: *(或对应域名) - 对比开启/关闭时的响应头:用
curl -I https://your.site/font.woff2查看实际返回的 header,确认Access-Control-Allow-Origin是否存在 - 注意:该问题在桌面 Chrome/Firefox 中通常不暴露,因其 CORS 字体策略较宽松;但 iOS Safari 和 WKWebView 强制校验,极易触发
Font from origin 'X' has been blocked from loading by CORS policy
安全可靠的解决方案
不建议全局关闭 sendfile(影响大文件传输性能),推荐按资源类型精准控制:
-
对字体等需 CORS 的静态资源禁用 sendfile:
在对应 location 块中显式关闭:
location ~ \.(woff2|woff|ttf|eot|svg|otf)$ {<br> sendfile off;<br> add_header Access-Control-Allow-Origin "*";<br> add_header Access-Control-Allow-Methods "GET";<br> add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range";<br> add_header Access-Control-Expose-Headers "Content-Length,Content-Range";<br>} -
确保 MIME 类型正确:Nginx 默认可能未正确识别
.woff2,在mime.types或 http 块中补充:
types {<br> application/font-woff2 woff2;<br> application/font-woff woff;<br> application/vnd.ms-fontobject eot;<br> font/ttf ttf;<br> font/svg svg;<br>} -
避免 add_header 被子 location 覆盖:确保 CORS 头在最内层 location 中设置,不要依赖上级块的
add_header(Nginx 默认不继承)
进阶优化(可选)
若担心 sendfile off 对字体性能影响(实际字体文件一般较小,影响极低),可考虑:
- 使用
tcp_nopush off;配合sendfile off,避免小文件分包问题 - 启用 Brotli/Gzip 压缩(字体本身不可压缩,但可减少传输量)
- 将字体托管至支持 CORS 的 CDN,并在 CDN 设置对应头(绕过 Nginx 层限制)


















