折腾的缘由
最近天杀的移动网经常抽风,我自己访问博客的速度非常慢,用这台服务器搭建的梯子速度也都非常慢,用宿舍网甚至速度跑不到100K/s!好在延迟不高,我又有没有money在香港等地租服务器QAQ,就想先加上cloudflare CDN勉强用着。
于是我给博客上了cloudflare CDN,地址是https://cdn.xmgspace.me。然而CDN下网页的样式却出现了大问题,很多样式加载异常,hitokoto和音乐播放器完全瘫痪。浏览器控制台报错如下:Access to XMLHttpRequest at <url> from origin 'https://cdn.xmgspace.me' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
原来遇到了跨域请求问题。
基础扫盲
啥是跨域请求?
在 HTML 中,<a>
, <form>
, <img>
, <script>
, <iframe>
, <link>
等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。[1]
因为安全问题,为防止CSRF攻击,浏览器通常会对跨域请求做出限制。
举例
a.example.com
对于:
a.example.com/api/index.php
不是跨域请求
b.example.com
是跨域请求
example.com
是跨域请求
问题分析
如果a.example.com
需要向b.example.com
请求的话,这种请求就属于跨域请求。如果在b.example.com
返回回来的响应头文件里有允许进行跨域访问的Header,那么就能进行正常请求。
下面是几种 HTTP 首部字段的简析:
- Access-Control-Allow-Origin
响应首部中可以携带这个头部表示服务器允许哪些域可以访问该资源,其语法如下:
Access-Control-Allow-Origin: <origin> | *
其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。
- Access-Control-Allow-Methods
该首部字段用于预检请求的响应,指明实际请求所允许使用的HTTP方法。其语法如下:
Access-Control-Allow-Methods: <method>[, <method>]*
- Access-Control-Allow-Headers
该首部字段用于预检请求的响应。指明了实际请求中允许携带的首部字段。其语法如下:
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
问题解决
可以从服务器,即对nginx进行设置:
如果a.example.com
需要向b.example.com
请求的话,在b.example.com
的nginx配置文件中加入以下配置:
location / {
#仅允许a.example.com的跨域请求
add_header Access-Control-Allow-Origin a.example.com;
#允许的请求方式
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
#允许的请求头
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
}
如果后端是php,也可以这样:
header("Access-Control-Allow-Origin: a.example.com");
现在cdn.xmgspace.me的大多数内容都可以正常加载了~但音乐播放器还有一些玄学问题。最近比较忙,这篇博文足足拖了5天QAQ...有时间在解决下吧!
参考资料
[1]. 什么是跨域请求以及实现跨域的方案](https://www.jianshu.com/p/f880878c1398)