1. 介绍

    为了增强学习过程中体感,通过演示代码模拟工作遇到的CORS跨域问题。演示代码中index.html页面使用ajax jquery调用php来重现工作中遇到跨域问题。( has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource和not allowed by Access-Control-Allow-Headers in preflight response )。通过此课程学习,可以了解跨域产生的原因以及如何解决常见跨域问题。 另外大家不用担心,对html、ajax、jquery、php不了解,也可以掌握CORS跨域问题的解决方法。因为演示代码只是为了重现错误,也便调试Nginx参数后,可以立即看到调试效果。

Nginx解决CORS跨域问题

2 准备演示环境

2.1 客户端配置:
上传工具: winscp
以windows 10为例:

配置hosts文件中添加以下内容

192.168.1.16 user.site.com
192.168.1.16 api.site.com
192.168.1.16 shop.site.com

附:
在修改hosts文件时遇到权限问题,可参考下图进行解决。以管理员身份来运行记事本,尔后在记事本---文件---打开---找到hosts文件 ( C:\Windows\System32\drivers\etc )

Nginx解决CORS跨域问题

2.2 服务器配置:

基础环境
操作系统: centos7.2
软件版本: nginx/1.16 PHP 7
软件安装方法: yum
使用的域名: api.site.com user.site.com shop.site.com

附件中演示代码对操作系统、nginx、php版本没有要求,浏览器只要能显示'phpinfo();'页面就能满足我们运行环境的需要。如果已经有PHP环境,确认phpinfo()能够正常显示就可以运行演示代码。

将附件中,“演示代码-本地请求-get_post请求/web-root”目录下的代码,上传到服务器/opt/app/code目录

如果以上配置一切顺利的话,通过浏览器访问http://user.site.com/index.html可以看到如下界面:

Nginx解决CORS跨域问题

3 CORS跨域资源共享

CORS全称是跨域资源共享(Cross-origin resource sharing),在学习CORS跨域之前,先了解一下相关概念,以便我们更好的理解跨域资源共享。

3.1 浏览器的同源策略

同源是指请求的两个URL中的协议、域名、端口三者完全相同。

Nginx解决CORS跨域问题

跨域请求是与浏览器发起请求URL不同源,就是一次跨域请求;

同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能被浏览器进行解析。浏览器同源策略默认阻止“跨域”获取资源。 实际工作场景我们是需要这种“跨域”操作的,这时我们可通过web服务器设置CORS响应头,来解决浏览器同源策略。

跨域图例:
Nginx解决CORS跨域问题

Nginx解决CORS跨域问题

跨域只是被浏览器阻止了,跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

3.2 CORS(跨域资源共享)

CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource sharing)。CORS是一个机制,它由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。 通过设置CORS添加HTTP头部信息可以绕过浏览器的同源策略;

Nginx解决CORS跨域问题

3.2.1 CORS请求类型

分为简单请求和非简单请求(预检请求)

简单请求
使用下列方法之一:
GET
HEAD
POST
Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded

预检请求
触发预检请求可以通过http请求中的PUT、DELETE方法、Content-Type类型不是简单请求中的、自定义http header头部信息; 后续我们会以自定义header头信息进行演示;

3.2.2 HTTP 请求头部字段

  1. Origin
  2. Access-Control-Request-Method
  3. Access-Control-Request-Headers

Nginx解决CORS跨域问题

3.2.3 HTTP 响应头部字段

  1. Access-Control-Allow-Origin
    Access-Control-Allow-Origin: <origin> | *
    Access-Control-Allow-Origin: http://user.site.com

  2. Access-Control-Max-Age
    指定了preflight请求的结果能够被缓存多久

  3. Access-Control-Allow-Credentials
    Access-Control-Allow-Credentials: true
    是否允许发送cookie信息
  4. Access-Control-Allow-Methods
    Access-Control-Allow-Methods GET POST 等

  5. Access-Control-Expose-Headers
    是否允许代码获得该字段,如需要应该设置此字段;

4 工作应用场景

4.1 正常请求

确认index.html文件内容url配置如下

var url = "/user.php";   //  请求当前目录下user.php
var url = "/tel.php" ;    //  请求当前目录下tel.php

Nginx解决CORS跨域问题

4.2 错误重现和解决

4.2.1 blocked by CORS policy

为满足业务发展的需要,技术人员进行代码优化;所有校验信息由api.site.com完成;

确认index.html文件内容url配置如下

var url = "http://api.site.com/user.php";  
var url = http://api.site.com/tel.php; 

Nginx解决CORS跨域问题

4.2.2 not ... ... in preflight response

Nginx解决CORS跨域问题

4.3 自定义域名跨域访问

任意子域名跨域访问
多域名跨域访问

4.4 只允许get或post方法

不生效 add_header 'Access-Control-Allow-Methods' 'GET';

nginx设置
只允许GET,但POST请求也可以通过。

add_header 'Access-Control-Allow-Methods' 'GET';

只允许POST,但GET请求也可以通过。

add_header 'Access-Control-Allow-Methods' POST;

简单请求会跳过此选项Access-Control-Allow-Methods ;

5 如何排查问题

5.1 nginx

打开日志的debug模式

5.2 浏览器

调出开发者工具 ,按F12调出、或快捷键 Ctrl + Shift + I 、或网页空白处右键 检查;
Nginx解决CORS跨域问题

5.3 抓包工具wireshark

5.4 tcpdump
tcpdump -i eno16777736 -nnntttvvv host 192.168.1.7 and ! port 22

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐