什么是跨域?
跨域,即浏览器试图执行其他网站的脚本。但是由于同源策略的限制,导致我们无法实现跨域。
如果两个url
的、域名、端口号完全一致,那么这两个url
就是同源的。
URL =协议+ 域名部分+端口部分+虚拟目录部分+文件名部分+参数部分+锚部分
同源策略即:不同源之间的页面,不准互相访问数据。
关于跨域的几个问题
为什么可以跨域使用CSS
、JS
和图片等?
同源策略限制的是数据访问,我们引用CSS
、JS
和图片的时候,其实并不知道其内容,我们只是在引用。
怎么跨域?
CORS跨域
什么是CORS?
CORS
的全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX
只能同源使用的限制。
如何理解CORS?
实现CORS
通信的关键是服务器。只要服务器实现了CORS
接口,就可以跨源通信。
两种请求
CORS
跨域分为两种请求,一种是简单请求,另外一种就是复杂请求。
简单请求
只要满足以下条件的就是简单请求:
- 请求方式为
HEAD
、POST
或者GET
- http头信息不超出以下字段:
Accept
、Accept-Language
、Content-Language
、Last-Event-ID
、Content-Type
(限于三个值:application/x-www-form-urlencoded
、multipart/form-data
、text/plain
)
简单请求的实现具体来说就是在信息头中加入一个Origin
字段:
GET /cors HTTP/1.1
Origin: http://fuwuqiname.com
Host: api.kehudaun.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0
...
复制代码
Origin
的作用就是用来说明本次请求来自哪个源,服务器会根据Origin
的值来判断是否接受本次请求。
对于简单请求,浏览器会直接发出CORS请求,它会在请求的头信息中增加一个Orign字段,该字段用来说明本次请求来自哪个源(协议+端口+域名),服务器会根据这个值来决定是否同意这次请求。如果Orign指定的域名在许可范围之内,服务器返回的响应就会多出以下信息头:
如果Origin
所表示的源不被服务器接受,即浏览器发现回应的信息头中没有Access-Control-Allow-Origin
字段,就会自动抛出一个错误。
Access-Control-Allow-Origin: http://api.kehudaun.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
复制代码
Access-Control-Allow-Origin
:该字段是必须的。它的值要么是请求时Origin
字段的值,要么是一个*
,表示接受任意域名的请求Access-Control-Allow-Credentials
: 该字段可选。它的值是一个布尔值,表示是否允许发送Cookie
。默认情况下,Cookie
不包括在CORS
请求之中。设为true
,即表示服务器明确许可,Cookie
可以包含在请求中,一起发给服务器。这个值也只能设为true
,如果服务器不要浏览器发送Cookie
,删除该字段即可。(注意:如果要发送cookie
,不仅要进行上述的设置,还要在AJAX
请求中设置withCredentials
属性)Access-Control-Expose-Headers
:该字段可选。CORS
请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定。
复杂请求(非简单请求)
非简单请求是对服务器有特殊要求的请求,比如请求方法为DELETE或者PUT等。非简单请求的CORS请求会在正式通信之前进行一次HTTP查询请求,称为预检请求。
浏览器会询问服务器,当前所在的网页是否在服务器允许访问的范围内,以及可以使用哪些HTTP请求方式和头信息字段,只有得到肯定的回复,才会进行正式的HTTP请求,否则就会报错。
预检请求使用的请求方法是OPTIONS,表示这个请求是来询问的。他的头信息中的关键字段是Orign,表示请求来自哪个源。除此之外,头信息中还包括两个字段:
- Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。
- Access-Control-Request-Headers: 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进行判断,如果返回的头信息在中有Access-Control-Allow-Origin这个字段就是允许跨域请求,如果没有,就是不同意这个预检请求,就会报错。
服务器回应的CORS的字段如下:
Access-Control-Allow-Origin: http://api.客户端.com // 允许跨域的源地址
Access-Control-Allow-Methods: GET, POST, PUT // 服务器支持的所有跨域请求的方法
Access-Control-Allow-Headers: X-Custom-Header // 服务器支持的所有头信息字段
Access-Control-Allow-Credentials: true // 表示是否允许发送Cookie
Access-Control-Max-Age: 1728000 // 用来指定本次预检请求的有效期,单位为秒
复制代码
只要服务器通过了预检请求,在以后每次的CORS请求都会自带一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
JSONP跨域
什么是JSONP?
jsonp的原理就是利用<script>
标签没有跨域限制,通过<script>
标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据
JSONP跨域缺点
- 具有局限性, 仅支持get方法
- 不安全,可能会遭受XSS攻击
Nginx代理跨域
websocket协议跨域
扩展url各部分组成:
- 协议部分:该URL的协议部分为“http:”,这代表网页使用的是HTTP协议。在Internet中可以使用多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。在"HTTP"后面的“//”为分隔符;
- 域名部分:该URL的域名部分为“www.aspxfans.com”。一个URL中,也可以使用IP地址作为域名使用
- 端口部分:跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(HTTP协议默认端口是80,HTTPS协议默认端口是443);
- 虚拟目录部分:从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”;
- 文件名部分:从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。本例中的文件名是“index.asp”。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名;
- 锚部分:从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分;
- 参数部分:从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“boardID=5&ID=24618&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符。