跨域问题及跨域问题方案汇总
目录
文章目录
内容
一、跨域问题的产生
1、同源策略
同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器封装了对同源策略的实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。
2、同源
所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。关于协议、域名系统、端口部分不懂的,可自行查阅相关文档,这里不在详述。
3、产生
出于浏览器的同源策略限制,当一个域去请求另外一个域的资源,跨域问题产生了。
4、示例及报错
当前页面url | 被请求页面url | 是否跨域 | 原因 |
---|---|---|---|
http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.test.com/ | https://www.test.com/ | 跨域 | 协议不同(http/https) |
http://www.test.com/ | http://www.baidu.com/ | 跨域 | 主域名不同(test/baidu) |
http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口号不同(8080/7001) |
报错示例:
- 控制台错误信息:
- network报错信息:
二、跨域请求分类
跨域请求可分为简单请求和非简单请求。
1、简单请求
满足以下条件,即为简单请求:
- 请求方法:GET、POST和HEAD 其中一种
- 请求头:Accept、Accept-Langue、Content-Language、Last-Event-ID Content-Type 不超过以上几种类型
- 请求类型:Content-Type 为一下三种中的任意一种
- text/plain: 文本
- applicaiton/x-www-form-urlencoded:&分隔的字符串编码
- multipart/form-data:表单提交,键值对编码
2、复杂请求
非简单请求则为复杂请求。复杂请求不同在于,在发送正式请求之前,发先发送OPTIONS请求,既预检请求。根据OPTIONS携带信息,服务器用来检测是否允许此次跨域请求。允许,则返回Status OK 。客户端正式发送接下来的请求;不允许,则拒绝,既产生上面所示的跨域问题。
二、跨域解决方案
tips :前端和代理解决方案是以后端提供跨域支持为前提,如果后端没提供跨域支持,则前端和代理方案不生效。
1、前端
- 通过jsonp跨域
- document.domain + iframe跨域
- location.hash + iframe
- window.name + iframe跨域
- postMessage跨域
参考地址1:https://segmentfault.com/a/1190000011145364不在详述
2、代理
既后端服务器软件环境,比如nginx,apache,windows server,tomcat. 这里以常用的nginx和apache为例,介绍下配置
- nginx 通用配置
#proxy服务器
server {
listen 80;
server_name www.test.com;# 示例网站
# 一下配置为开放测试环境,生成环境根据需求自行更改
# 此处为设置全局跨域
add_header Access-Control-Allow-Origin *; #当前端只跨域不带cookie时,可为*,*通配符任意通常做开放测试
add_header Access-Control-Allow-Credentials true; # 表示运行携带cookie
add_header Access-Control-Allow-Methods: "OPTIONS, HEAD, GET, POST, PUT, DELETE";
add_header Access-Control-Allow-Headers: "Origin, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With";
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
# 如果在此处设置则为此路径下跨域设置
index index.html index.htm;
}
}
- apache
# www.text.com 虚拟主机
<VirtualHost *:80>
# 设置网站目录
DocumentRoot "xxx"
# 设置网站名称
ServerName www.text.com
# 错误日志
ErrorLog "xxx/logs/error.log"
# 普通日志
CustomLog "xxx/logs/access.log" combined
FcgidInitialEnv PHPRC "xxx/Extensions/php/php7.3.4nts"
AddHandler fcgid-script .php
FcgidWrapper "xxx/php/php7.3.4nts/php-cgi.exe" .php
# 设置跨域位置1
#Header set Access-Control-Allow-Origin *
# Header set Access-Control-Allow-Credentials true
# Header set Access-Control-Allow-Headers
# Header set Access-Control-Allow-Methods
# 设置目录访问权限
<Directory "E:/phpstudy_pro/WWW/php/tp5/public">
Options +Indexes +FollowSymLinks +ExecCGI
AllowOverride All
Order allow,deny
Allow from all
Require all granted
# 设置位置2
# Header set Access-Control-Allow-Origin *
# Header set Access-Control-Allow-Methods "OPTIONS, HEAD, GET, POST, PUT, DELETE"
# Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
# 网站默认首页
DirectoryIndex index.php index.html
</Directory>
</VirtualHost>
上面有2除位置可以设置,任选其一即可。同样用于开放测试,生成环境根据需要自行调整
3、后端
-
解决问题的根源还是在后端,既设置4个响应的请求头:
- Header set Access-Control-Allow-Origin # 运行那些域名的访问,既访问来源
- Header set Access-Control-Allow-Credentials # 是否允许携带cookie
- Header set Access-Control-Allow-Headers # 允许那些请求头,默认的除外
- Header set Access-Control-Allow-Methods # 允许请求的方法:OPTIONS,HEAD,GET,POST,PUT,DELETE等等
-
根据是开发环境还是生成环境设置也会不同。
-
根据不同后端语言,实现接口会有不同。主流后端语言,比如 php,java,(c)c++, nodejs,python等等,提供详细自行查阅相关文档。
3.1、php
原生自行查阅相关文件,这里只介绍目前比较流行的php框架之一thinkphp解决方案中OPTONS预检处理。既通过拦截请求,检测请求方法是否是OPTIONS。如果是,然后检测是否符合要求,符合要求就返回status ok ;不符合要求就拒绝。
具体参考地址2:https://blog.csdn.net/marswill/article/details/82877069
3.2、java
参考地址3:https://blog.csdn.net/u013929107/article/details/97611891
3.3、python
参考地址4:https://www.cnblogs.com/mqhpy/p/11445071.html
3.4、nodejs
参考地址5:https://blog.csdn.net/weixin_39559301/article/details/89855669
tips : 目前流行框架开发,都提供相应的跨域接口,或者类似拦截器功能,很方便解决跨域问题。
4、主流解决方案CORS
CORS(Cross-Origin-Resource-Share),既跨域资源共享,
目前主流的跨域解决方案的方式既CORS(Cross-Origin-Resource-Share),既跨域资源共享。
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。
目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
说白了,既会产生跨域的各方协调设置跨域解决方案。
1、解决方式
- 前端+后端
- 前端+代理+后端OPTIONS处理
2、具体分析
- 前端: 前端目前常用发送网络请求为ajax和axios。总所周知是ajax有安全问题,现在更推荐使用的axios。其他的资源请求,参考上面。
- 后端:请看上面部分,不在详述。
tips 后端和代理不需要同时设置,但是后端必须设置OPTIONS处理方法,除非所用框架或者模块提供默认的解决方案。
三、效率问题
复杂跨域请求,要发送一次预检请求,那么必然影响访问效率,这个怎么解决呢?我们能想到的问题,开发人员自然也早就提我们想好了,那就是第一次预检请求通过后,会设置一个响应头,Access-Control-Max-Age: 自定义时间。一般不需要显示设置,除非是原生开发。
后记 :参考了不少博客,主要是做了下总结梳理,下面列出博客地址,如有问题,欢迎交流,本人QQ:806797785.
参考链接1:https://segmentfault.com/a/1190000011145364
具体参考地址2:https://blog.csdn.net/marswill/article/details/82877069
参考地址3:https://blog.csdn.net/u013929107/article/details/97611891
参考地址4:https://www.cnblogs.com/mqhpy/p/11445071.html
参考地址5:https://blog.csdn.net/weixin_39559301/article/details/89855669
再次感谢。