要快乐,不要跨域……

一晃眼一周就又过去了,一不小心就被叶子同学催稿了,但总算在周三这天发了出去. 叶子同学本周带大家初步了解了下TS,那本周查查就讲讲跨域那点事~

跨域,一定是我工作以来碰到最多的问题,每次都要和后台研发扯一会,有时候就很纳闷~既然本篇的内容是关于跨域,那必须先解释一下什么是跨域了,引用MDN上的解释:当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。其实我觉得解释的不是很清楚,通俗一点讲的就是:我访问域A,然后域A的代码中需要请求数据,或者是图片,然后域A发起请求,这个请求需要去访问域B下的接口,域A和域B,在协议、域名、端口号中有一样不一致的,那么...就会产生跨域!

那什么是,什么又是端口呢?

那就拿百度的域名来说吧,百度www.baidu.com,其实它完整的域名是https://www.baidu.com:80,https是该域名的通信协议,关于通信协议这边大概讲一下,通信协议一般被提起较多的是是七层协议或者是说四层协议.七层协议,一般包括物理层,数据链路层,网络层,传输层,会话层,表示层,应用层.四层协议只是对其进行了概括,笼统的分为了应用层,传输层,网络层,网络接口层.HTTP和HTTPs是归属于应用层一类,我们熟知的TCP,UDP是属于传输层协议,TCP是较为安全的传输层协议,会通过三次握手(前端同学可以了解一下)建立起会话,这种操作其实是为了避免数据的丢失.

IP则是网络层协议.好了好了.感觉有点跑偏了~又把自己通信专业的老本行拿了出来.

不知道为什么,查查写这几个域名的时候有种看到康师傅和康帅傅的感觉....,傻傻分的清楚了吗~划重点~划重点~同一个域名下不同的文件夹是属于同一个域名下的哦

我们是一个域名哦

端口号是具有网络功能的应用软件的标识号,端口号是不固定的,可以受到分配,也可以是其默认的端口号.其中http协议的端口号默认是80,我这边列举几个常见的端口号吧~

443 ===>https

22 ===> SSH安全登录,文件传送和端口重定向

21 ===> FTP文本传输(常见的FileZilla传输文件常用)

23 ===> Telnet不安全的文本传输

25 ===> SMTP 简单邮件传送协议

以上是通常造成跨域的原因.

好了,讲了这么多周边知识,要开始切入正题了~

下面我以几个新手经常遇到的问题开始解析:

1. 当我去请求接口的时候,为什么在控制台netWork中有数据返回,但是页面就没有,而且还报跨域错误呢?

首先,跨域限制是浏览器行为,是浏览器出于安全考虑做的限制.我们在请求数据的时候确实是请求了,而且有返回,但是浏览器根据response的header发现和当前页面不是同源,那么就其返回的数据限制了.如果是在开发环境,后台接口那边没有配置跨域,但是你又非常想获取到数据,那么也有解决的方法.

第一种:chrome插件里面有个CORS,可以简单粗暴的解决,当然前提是你能科学上网咯~如果不能科学上网的话请采用第二种方式.

第二种:我们可以通过使用chrome命令行启动参数来改变chrome浏览器的设置

window下:找到桌面chrome浏览器图标,右键“属性” 如图:

在目标后面加上 --disable-web-security --user-data-dir(注意--前面有空格)点击确定,然后打开浏览器出现

如果你是Mac 那就很简单了,退出浏览器,然后输入命令行:

open -a /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir

是不是觉得这种方法简单粗暴,但是这只是暂时的解决方案,毕竟终极大Boss还是没KO,那我们继续....

我们一般发出去的请求会被分为简单请求和复杂请求(预检请求)

简单请求

需要(同时)满足以下条件:

请求方式为以下其中之一

GETHEADPOST

2 请求头的集合为以下排列组合

AcceptAccept-LanguageContent-LanguageContent-Type (需要注意额外的限制)DPRDownlinkSave-DataViewport-WidthWidth

3.Content-Type 为以下其中之一

text/plainmultipart/form-dataapplication/x-www-form-urlencoded

我又访问了一下淘宝网的首页,随便找了个接口,虽然这是个请求图片的请求,但是还是有我们需要看的东西

下面一部分是请求头,我们可以看到Origin字段表明该请求来自https://www.taobao.com然后上面一部分是响应头,在一行中携带了响应首部字段 Access-Control-Allow-Origin,服务端返回了Access-Control-Allow-Origin: * 表明,该资源可以被任意外域访问。那服务器端如何设置Access-Control-Allow-Origin: * 呢?

这边查查也把解决方案贴一下,可以通过Nginx来解决,在nginx.conf中配置

addheader 'Access-Control-Allow-Origin' '*';addheader 'Access-Control-Allow-Methods' 'POST,GET,PUT,DELETE,OPTIONS';addheader 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since';addheader 'Access-Control-Allow-Credentials' 'true';

如果想进一步去了解Nginx的,可以去看看文档

复杂请求(预检请求)

需要满足以下(任意一条)条件的:1 请求方式为以下其中之一

PUTDELETECONNECTOPTIONSTRACEPATCH

2 设置了非简单请求的请求头字段

3 Content-Type 为非简单请求的其他值

下面的例子是一个复杂请求,需要先发送OPTIONS请求,然后根据OPTIONS的返回去发送实际的请求

从第一张图看出,请求头的'Content-Type',被设置为'application/xml',不属于简单请求之一,而且还人为的设置了字段'X-PINGOTHER', 'pingpong',所以该请求是一个复杂请求,然后我们看到第一张图的Access-Control-Allow-Methods,也就是后面能够接受的请求方式可以为POST,GET,OPTIONS其中之一,而我们的请求是POST请求刚好满足条件,所以实际的请求是被服务器所允许的.

但是...(为什么总有那么多但是),有的请求需要带身份凭证,这个凭证可以通过 HTTP cookies 和 HTTP 认证信息发送 ,一般来说一些登录信息需要以HTTP Cookies的形式传输.但对于跨域的请求,浏览器是不会发送身份凭证信息的,如果需要发送,就需要设置一些参数.

withCredentials = true

这个时候响应头则会返回

Access-Control-Allow-Credentials: true

如果需要发送身份凭证,那么服务器不能设置为Access-Control-Allow-Origin:*这边又是为什么呢?首先Access-Control-Allow-Origin为星号时,是允许所有外域访问的,一旦我们发送带有身份信息的请求时,容易使身份信息被劫持,是一种不安全的行为.所以需要发送身份凭证的时候需要在服务器上指定请求Origin的域.

好了,这周就讲到这了,还好没拖稿,啊哈哈!886,下周见~

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180725G0UO4A00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券