跨域问题
什么是跨域
什么是同源策略
同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制的内容
- Cookie、LocalStorage、IndexedDB等存储性内容
- DOM节点
- AJAX请求发送后,结果被浏览器拦截了
但是有三个标签是允许跨域加载资源的
<img src=XXX>
<link href=XXX>
<script src=XXX>
常见的跨域场景
当协议、子域名、主域名、端口号任意一个不相同时,都算作不同域。不同域之间请求资源就算作“跨域”。
注:跨域请求并不是请求发不出去,请求是可以发送的,服务端也可以收到请求并正常返回,但由于浏览器的同源策略,响应结果被拦截了
跨域解决方案
JSONP
-
JSONP的原理:
利用
<script>
标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。 -
JSONP的实现流程:
比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是http://damonare.cn/data.php,那么a.html中的代码就可以这样:
<script type="text/javascript"> function dosomething(jsondata){ //处理获得的json数据 } </script> <script src="http://example.com/data.php?callback=dosomething"></script>
我们看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。
因为是当做一个js文件来引入的,所以http://damonare.cn/data.php返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的(一定要和后端约定好哦):
<?php $callback = $_GET['callback'];//得到回调函数名 $data = array('a','b','c');//要返回的数据 echo $callback.'('.json_encode($data).')';//输出 ?>
最终,输出结果为:dosomething(['a','b','c']);
如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。
<script type="text/javascript"> $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){ //处理获得的json数据 }); </script>
jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。
-
JSONP的优缺点
-
JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。
-
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
-
CORS跨域
-
CORS原理
CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
浏览器的请求头重会含有
origin
的头信息,用来表明请求的来源。而服务器一个响应头信息Access-Control-Allow-Origin
,如果这两个头的内容匹配,则可以实现跨域。 -
两种请求
-
简单请求
只要同时满足以下两大条件,就属于简单请求
条件1:使用下列方法之一:
- GET
- HEAD
- POST
条件2:Content-Type 的值仅限于下列三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
-
复杂请求
复杂请求是对服务器有特殊要求的请求,比如请求方法是
PUT
、DELETE
,或者Content-Type
的字段类型是application/json
。复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是
OPTION
方法的,通过该请求来知道服务端是否允许跨域请求。预检请求的HTTP头信息:
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT /浏览器CORS请求用到的HTTP方法 Access-Control-Request-Headers: X-Custom-Header /CORS额外发送的透信息字段 Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
服务端收到预检请求以后,检查完信息允许跨源请求,作出回应。
TTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com //表示该接口可以请求 Access-Control-Allow-Methods: GET, POST, PUT //返回支持的跨域请求方法 Access-Control-Allow-Headers: X-Custom-Header //支持所有头信息字段,不限于浏览器“预检”中请求的字段 Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
-
Nginx反向代理
使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
先下载nginx,然后将nginx目录下的nginx.conf修改如下:
// proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
复制代码
最后通过命令行nginx -s reload
启动nginx
// index.html
var xhr = new XMLHttpRequest();
// 前端开关:浏览器是否读写cookie
xhr.withCredentials = true;
// 访问nginx中的代理服务器
xhr.open('get', 'http://www.domain1.com:81/?user=admin', true);
xhr.send();
复制代码
// server.js
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var params = qs.parse(req.url.substring(2));
// 向前台写cookie
res.writeHead(200, {
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly:脚本无法读取
});
res.write(JSON.stringify(params));
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
搬运文章
什么是CDN,CDN回源是什么
什么是CDN
CDN(Content Delivery Network)即内容分发网络。通过网络各处放置节点服务器,CDN可以实时的根据网络流量和各节点的连接、负载状况以及与用户的距离等情况将用户的请求导向离用户最近的服务节点上。
CDN访问流程
- 当用户点击URL后,经过本地DNS服务器的解析,DNS服务器会最终将域名的解析权交给CNAME里指向的CDN专用的DNS解析服务器。
- CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回给用户
- 用户向CDN的全局负载均衡设备发出请求
- CDN的全局负载均衡设备根据用户的IP地址以及内容请求的URL,选择一台用户所属的区域负载均衡设备,告诉用户向这台设备发出请求
- 区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务。根据用户的IP地址,判断哪一台服务器距离用户最近,根据用户请求的URL中携带的内容判断哪一台服务器有用户所需内容,查询服务器当前负载情况,判断哪一台服务器尚有服务能力。根据以上条件分析之后,区域负载均衡设备将缓存服务器的IP地址返回
- 用户向缓存服务器发出请求,缓存服务器响应用户请求。如果这台服务器没有用户想要的内容,那么这台服务器会向上一级请求内容,直至追溯到网站的源服务器将内容拉到本地。
那么回源是什么意思
当 CDN 缓存服务器中没有符合客户端要求的资源的时候,缓存服务器会请求上一级缓存服务器,以此类推,直到获取到。最后如果还是没有,就会回到我们自己的服务器去获取资源。 那都有哪些时候会回源呢?没有资源,资源过期,访问的资源是不缓存资源等都会导致回源。