跨域问题及跨域解决方案汇总

跨域问题及跨域问题方案汇总


目录


内容

一、跨域问题的产生

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、前端

  1. 通过jsonp跨域
  2. document.domain + iframe跨域
  3. location.hash + iframe
  4. window.name + iframe跨域
  5. 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

再次感谢。

发布了17 篇原创文章 · 获赞 3 · 访问量 2689

猜你喜欢

转载自blog.csdn.net/gaogzhen/article/details/103827929