看完对于跨域还有疑问,请顺着网线过来打死我

本文涉及的产品
.cn 域名,1个 12个月
简介: 跨域,在前后端分离的项目中是很常见的一个问题,跨域是对于浏览器操作来说的,脱离了浏览器来谈跨域是没有任何意义的,笔者目前所在的项目组就是一个前后端分离的项目,也出现过跨域问题,这里对跨域以及跨域涉及到的CORS、OPTIONS请求、Referer字段、Origin字段等信息做个总结。这篇文章分三个步骤去总结跨域问题,第一部分介绍什么是跨域,以及跨域相关的一些概念;第二部分介绍跨域带来的问题有哪些。第三部分总结解决跨域问题的方式。

前言:

跨域,在前后端分离的项目中是很常见的一个问题,跨域是对于浏览器操作来说的,脱离了浏览器来谈跨域是没有任何意义的,笔者目前所在的项目组就是一个前后端分离的项目,也出现过跨域问题,这里对跨域以及跨域涉及到的CORS、OPTIONS请求、Referer字段、Origin字段等信息做个总结。这篇文章分三个步骤去总结跨域问题,第一部分介绍什么是跨域,以及跨域相关的一些概念;第二部分介绍跨域带来的问题有哪些。第三部分总结解决跨域问题的方式。


一、跨域



1.什么是跨域?


跨域这个概念是对于前端来说的,准确的说是对于浏览器来说的,因为安全问题,浏览器会禁止js访问非同源的资源,访问非同源的资源就是跨域。那什么样的资源才算是同源呢?同源需要同时满足以下三点:


1)通讯协议相同

2)域名或者ip相同

3)端口相同


当浏览器发出的请求,更具体点的说是js发出的资源请求,对于以上三者有任何一个不满足,都属于跨域,假如请求发起地址是这个:http://huawei.one.two/,当访问如下地址时的跨域情况如下:


1)https://huawei.one.two/ 通讯协议不同,这里访问的是https,属于跨域

2)http://huawei.one.three/ 域名不同,也属于跨域

3)http://huawei.one.two:8080/ 原端口是默认的80端口,端口不同也属于跨域。

4)http://huawei.one.two/supplier/queryDetails 这里访问的是相同的通讯协议、相同的域名、相同的端口,虽然地址有区别,但是不是跨域。


2.浏览器为什么要禁止跨域?允许跨域有什么隐患?


前面简略的说了下,因为安全问题,浏览器禁止了跨域的请求,跨域的最典型的安全问题体现在Cookie中,我们知道Cookie中会缓存登录信息,跨域时Cookie信息是不会共享的,假如Cookie中的登录信息可以共享,这很明显会有极大的安全隐患。举个例子:A用户登录了中国银行账户系统,在未退出的情况下,又访问了某动作片网站,动作片网站中电影图片链接的不是影片地址,而是中国银行的转账支付链接,此时A用户点击了这个电影。那么此时用户点动作片电影时就变成了进入中国银行去转账了,因为浏览器也允许跨域,所以此时Cookie信息共享,A用户访问的转账地址携带了Cookie中的登录信息。银行一看是用户A的正常操作,转账就成功了。这就是允许跨域的最典型的问题,所以浏览器会禁止跨域访问,禁止跨域请求,跨域时Cookie信息不共享。所以总结来说,禁止跨域就是为了保护用户的信息安全,就是为了Cookie、localStorage等中的信息不回被非同源的网站窃取。


3.跨域时有什么体现


说到跨域的体现就必须要说OPTIONS请求了,因为跨域总是伴随着OPTIONS请求的,那什么是OPTIONS请求呢?下面先来介绍下OPTIONS请求。


3.1 什么是OPTIONS请求?


Http请求总共有8种,OPTIONS,就是其中一种;这八种请求方式分别是:GET、POST、HEAD、OPTIONS、PUT、DELETE、TRACE、CONNECT。这把八种请求中OPTIONS之前的三个请求GET、POST、HEAD是简单请求类型,OPTIONS之后的四种就是复杂请求了,也可叫重请求。


3.2 OPTIONS请求有什么作用?


已经知道OPTIONS请求是八种Http请求的一种,那他有什么作用呢?他的作用官方给出的解释有两种:

  • 1)获取服务器支持的HTTP方法。
  • 2)检查服务器性能。


这就是OPTIONS的作用了,在跨域时,浏览器会先向服务器发送一个OPTIONS请求,用来判断服务器是否支持跨域的操作,假如服务支持跨域的话服务器需要在响应的头信息中加入Access-Control-Allow-Origin来声明允许跨域的域名;加入Access-Control-Allow-Methods来声明允许的请求方式。下面就是一个跨域时的OPTIONS请求案例:

20210529151732124.png


如果服务器不支持跨域的话,会响应一个错误码过来,此时第二次的真实请求是不会发送出去的。


3.3 哪些场景会触发OPTIONS请求


前面说跨域会触发OPTIONS请求,事实上不止跨域会触发OPTIONS请求,这只是OPTIONS被触发的一种情况,此外还有两种情况会触发OPTIONS请求,这里一起总结下三个场景。


1)跨域时会触发OPTIONS请求,用以判断服务器是否支持跨域操作,上面已经说了允许跨域时需要在Access-Control-Allow-Origin、Access-Control-Allow-Methods的这两个字段进行声明允许的跨域的域名和允许的请求方式,如下图:

2021052915310325.png


2)简单请求时(GET、POST、HEAD)添加了自定义的头部信息、Content-type不是这几种类型application/x-www-form-urlencoded、multipart/form-data、text/plain此时会触发OPTIONS请求。此时需要去服务器验证是否支持自定义请求头,如果不支持会返回相应状态码,如果支持,则会在返回的响应头中的这个Access-Control-Allow-Headers:中进行声明,如果支持自定义头部的话,这个字段的值要么是列出支持的字段,要么是*,如下图所示:


20210529152824100.png


3)复杂请求(PUT、DELETE、TRACE、CONNECT)都会触发OPTIONS请求。但是这些请求一般不会使用,正常的服务都会禁用这些请求方式。


二、跨域导致了什么问题



1.请求无响应


前面已经说过如果服务器允许跨域,会在响应头中加入Access-Control-Allow-Origin这个字段标注允许跨域的域名,这个域名还必须与OPTIONS请求发起时Origin中的值相同,当浏览器收服务器响应的信息时,会在头中检查Access-Control-Allow-Origin这个字段的值,若是与Origin不匹配,则不会将请求信息返回给用户看到,此时体现的就是请求无响应。这里解释下Origin字段,这个字段是只有在POST请求中才会出现,作用是标注请求发起的源或者说位置。Origin与另一个字段Referer有些类似,Referer作用也是标注请求发起的位置,只不过所有的请求中都会有Referer。Origin和Referer通常被用作预防CSRF攻击的判断,下面第一张图是GET请求,只有Referer没有Origin。第二张图是POST,两者则都有。如果对于CSRF有些疑问可以看这里:一文从容应对CSRF。


20210529163704325.png20210529163952526.png


2.请求发送不出去


有时候就会出现这种情况,笔者也是碰到过:浏览器访问的网页正常,但是点击功能时一直都没有响应,然后打开F12查看network时发现浏览器压根就没有将请求发送出去,这是为何?当时也是百思不得琦姐,后来才知道这个也是跨域引起的问题,当时运维反映说是变更了网略策略导致的这种情况,具体操作,笔者也是不清楚,但是这个问题的根本原因是跨域引起的,若是碰到类似问题,解决跨域问题这个问题也就解决了。


3.哪些项目会有跨域问题


上面已经说了跨域的条件,仔细一想便可以发现,只有前后端分离的项目才会碰到跨域问题,而且一定会碰到。因为前后端分离时,前端是一个独立的服务,后端是一个独立的服务或者集群。若是前后端服务部署在同一服务器,那他们接口肯定不同,部署在不同服务器他们ip不同,所以前后端分离的项目肯定会碰到跨域问题,而前后端不分离的项目则不会有这种问题,因为请求的都是同源的资源。那么如果碰到了跨域问题怎么解决呢?


三、如何解决跨域的问题



1.通过服务器代理解决跨域(推荐)


对于前后端分离的项目一定是有跨域问题存在的,目前主流的解决方案就是使用NGINX的反向代理,前端配置相对路径,根据NGINX的配置代理后端地址,这样就解决了跨域的问题,与前端交互的是NGINX服务器,就不会有跨域问题,NGINX服务器与后台交互也不会有跨域,这样就可以解决跨域的问题,这种方式笔者认为还是比较简单的,若是对于NGINX的配置不太清楚,可以去b站上搜搜教学视频,NGINX的使用还是很简单的。


2.CORS解决跨域(推荐)


CORS(跨域资源共享:Cross-origin resource sharing)是W3C的标准,这个标准允许浏览器跨域对服务器的资源进行访问,只不过前端在发起请求是需要使用XMLHttpRequest进行发起,目前主流的浏览器都支持CORS,所以这是一种行之有效的解决方案。在使用这种方案解决跨域时,需要服务端的同时支持。服务端要如何改动呢,这里以SpringBoot(SpringCloud类似)构建的项目为例来进行演示服务端如何允许跨域的访问。这里可以细分为两种方案,一种是全局式的解决方案,一种是方法级别的解决方案。


2.1 服务端全局解决方案


我们需要在前端配置适配器(WebMvcConfigurerAdapter)中来进行相关的配置,代码如下所示,这样就完成了CORS的后端支持,前端则不需要配置什么,因为前端默认就是支持的。这样服务端的跨域问题就解决了。

@Configuration
public class WebInterceptorConfiguration extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//允许被跨域访问的地址
                .allowedOrigins("http://sworkp.esgcc.com.cn")//允许跨域的域名,对应响应头中的:Access-Control-Allow-Origin
                .allowCredentials(true)//跨域是否允许使用Cookie信息,对应响应头中的:Access-Control-Allow-Credentials
                .allowedHeaders("*")//头部允许的自定义参数,对应响应头中的:Access-Control-Allow-Headers
                .allowedMethods("POST","GET","OPTIONS")//允许的请求方法,对应响应头中的:Access-Control-Allow-Methods
                .maxAge(1800);//配置客户端缓存预检请求的响应的时间(以秒为单位)。默认设置为1800秒(30分钟)。
    }
}


(注意:SpringBoot2.3 通过继承WebMvcConfigurerAdapter该类,2.4以后的版本需要实现WebMvcConfigurer该接口,因为SpringBoot2.4以后废弃了WebMvcConfigurerAdapter该类,不过方法内部的操作没有区别。)


2.2 服务端方法级解决方案


在方法层面控制是否跨域我们只需要一个注解CrossOrigin即可,该注解就是专门用于控制跨域访问的注解。CrossOrigin使用在类层面上代表该类下所有接口均可被跨域访问,使用在方法上则只有被该注解标注的方法才可以被跨域访问。该注解支持的属性与第一种通过配置的没有什么区别,所以建议还是使用全局配置更为方便,但要是追求灵活性还是需要使用注解,注解的使用形式如下:

@CrossOrigin(origins = "http://www.baidu.com"
    ,allowCredentials = "false"
    ,methods = RequestMethod.POST
    ,maxAge = 1800,allowedHeaders = "*")
@RestController("/supplier")
public class SupplierController {
  @PostMapping("/query")
  public void queryDetail(String oid){
  }
}


3.JSONP解决和webSocket解决(不推荐)


这两种方法都是已经过时的解决方案,当下主流的肯定不会使用,CORS已经完美的取代了JSONP,webSocket使用场景也很少,笔者认为没有必要去研究这两种策略了,这里给出一位作者关于这两点的解释,供有需要的人作为参考:点击这里查看


四、总结



这里介绍了什么是跨域,跨域的危害、哪些情况会有跨域、怎么解决跨域,尤其是前后端分离的项目,跨域是必须解决的问题,笔者也是碰到过类似的问题,希望这里的微薄分享可以对路过的你有所启发。

相关文章
|
2月前
|
网络协议 网络安全 网络架构
不会这10个抓包技巧,就不要在网工圈里混了!
不会这10个抓包技巧,就不要在网工圈里混了!
|
12月前
|
数据采集 Prometheus 监控
自建稳定的HTTP代理池(妈妈再也不用担心被封了) | 实用教程
对于爬虫技术人员来说,自建HTTP代理池是提高爬虫效率和成功率的关键一环。今天,我们来聊聊怎么搭建稳定高效的自建HTTP代理池。
|
前端开发 文件存储 数据安全/隐私保护
【小刘带你玩儿前端】什么是跨域以及如何解决?
现在的web项目,很多都是前后端分离,特别容易出现跨域问题
【小刘带你玩儿前端】什么是跨域以及如何解决?
|
网络协议
面试官神级问题:DNS服务器是否可以加快我们的网络访问速度?
众所周知,DNS服务器在网络访问中起着极其重要的作用,它将 URL 域名转换为 IP 地址以供设备访问,既然DNS服务器可以承担将URL域名转换为IP地址的任务,那么DNS服务器是否可以加快我们的网络访问速度呢?
484 0
面试官神级问题:DNS服务器是否可以加快我们的网络访问速度?
|
存储 网络协议 数据安全/隐私保护
邮件传输的过程都看不懂。那我走(狗头)
给学习网络的新手一个我自己总结的建议: 我觉得学网络先要先把最基础最常用的协议的原理搞的明明白白,然后再学习难的协议或者是拓展的协议就好理解容易上手了。
217 0
邮件传输的过程都看不懂。那我走(狗头)
|
安全 网络协议 程序员
内网穿透---IPv6点对点【妈妈再也不用担心网速了】
IPv6时代来临,为内网应用打开一片新天地。 书接上回(有关smarGate使用,请看“系列一”文章,自行度娘smarGate), smarGate是一个免费的内网穿透利器,如果你有以下需求,不要犹豫,用smarGate,让免费来的更彻底! 诉求一: 我是程序员或运维人员,我没有公网服务器,我希望访问自己或公司的位于局域网中的机器,我对带宽没要求,就是做些程序员做的事:ssh登录操作,我需要安全访问。
11656 0
我需要一台好点的服务器
知道 Jira 这个项目管理工具已经很长时间,尤其在国外非常流行,最早给国外客户做项目时很多提供的项目管理系统就是 Jira。 关于Jira 你还应该知道以下几点: Jira 是 atlassian 公司的产品,公司位于澳大利亚 去年, atlassian 还收购另一个很出名任务管理系统 trello 目前 Jira 分 Cloud 云端版和Server版,前者不用安装管理,后者需要有自己的服务器 Jira 可以免费试用30天 Jira 运行后打开网页比较慢,因为不是SPA,也可能比较占内存。
838 0