本文总结自极客学院跨域Ajax实现视频教程地址
常用的Ajax跨域请求有:CORS(跨域资源共享)、JSONP跨域和iframe跨域通信
一、CORS原理:
xhr level2支持的新标准,XMLHttpRequest随想原生支持ajax,支持xhr level2的浏览器就能发起ajax跨域请求。但是它也有一定的安全限制,并不是支持了xhr level2的浏览器就能直接发起ajax跨域请求,只是说,它在标准上有实现跨域的功能,我们需要通过一定的安全策略,让这个功能真正的支持起来。
二、CORS实现
- 实现CORS跨越请求关键在于,如何通过安全策略的设置,让跨域ajax的功能真正的发起。
- 当浏览器判定一个请求为跨域请求时,它会在请求头信息中查找,是否存在一个“Access-Control-Allow-Origin”字段,并且该字段的值是允许一个域向另一个域发起请求的,这时请求就会被通过。
- 当我们向一个域发起请求时,后端实际上已经将结果相应给了前台,但是前台是否能够使用后台返回的数据,并交给前端脚本处理,取决于响应信息中是否有一个允许使用的标志(Access-Control-Allow-Origin),它的值就是允许访问的域(如:a.test.com)。如果我们希望一个域(a.test.com)能够访问另一个域(b.test.com),那么另一个域(b.test.com)的响应信息中就必须包含允许访问的标志,它的值就是我们发起请求的域的名称(a.test.com)
三、CORS跨域资源共享分类
- 简单请求:浏览器直接发出CORS请求,具体来说,就是在头信息中,增加一个Origin字段,用来说明本次请求来自哪个源(协议+域名+端口),服务器根据这个值,决定是否同意这次请求。
1.根据服务器的返回头信息是否包含“Access-Control-Allow-Origin”字段,来判断请求是否出错(“Access-Control-Allow-Origin”字段是必须的,它的值要么是Origin字段的值,要么是一个星号“*”,表示接受任意域名的请求。)
2.CORS请求默认不发送Cookie和Http认证信息,如果要把Coolie发送到服务器,一方面要服务器同意,另一方面,开发者要在Ajax请求中打开“withCreditials”属性:
var xhr = new XMLHttpRequest();
xhr.withCreditials = true;
- 非简单请求:对服务器有特殊要求的请求,比如请求方式是 “PUT”或“DELETE”等。
非简单请求的CORS请求会在正式通信前,增加一次HTTP查询请求,成为“预检”请求(Preflight)。预检请求用的请求方式是“OPTIONS”,表示该请求时用来询问的,关键字段是Origin。
三、CORS跨域演示
修改host文件来模拟跨域(C:\Windows\System32\drivers\etc)
在host文件中添加:
127.0.0.1 a.test.com
127.0.0.1 b.test.com
便可利用a.test.com和b.test.com来模仿两个域,实现跨域请求。
此处演示用node.js来作后台处理。
- package.json文件
{
"name": "ajax-cross-domain",
"description": "cross ajaxs",
"version": "0.0.1",
"main": "./app.js",
"dependencies": {
"express": "4.x",
"body-parser": "*"
}
}
- app.js
var express = require('express');
var path = require('path');
var bodyParer = require('body-parser');
var app = express();
app.use(bodyParer.json());
app.use(bodyParer.urlencoded({
extended: false
}));
app.use(express.static(path.join(__dirname,'public')));
/*设置响应头信息,在这里做一个头信息通用设置,即在发起请求前设置,达到在一个位置设置,所有位置都能生效的效果*/
app.use(function(req,res,next) {
res.header("Access-Control-Allow-Origin", "a.test.com");
//设置响应头信息,若想让所有请求域都通过,可以将值设置为“*”
res.header("Access-Control-Allow-Headers", "test");
res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
next();
});
app.use('/',require('./routes/index.js'));
var DEFAULT_PORT = 3000;
app.listen(DEFAULT_PORT);
console.log('server is listen at port: %d',DEFAULT_PORT);
- index.js
/**
* Created by lenovo on 2016/8/4.
*/
var express = require('express');
var router = express.Router();
router.all('/',function(req,res) {
res.sendFile('./public/index.html');
});
router.all('/test',function(req,res) {
res.send('ok');
});
module.exports = router;
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cors</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/jquery-1.11.3.js"></script>
</head>
<body>
<div class="container">
<button class="btn btn-primary" onclick="crossAjax()">CORS</button>
</div>
<script>
function crossAjax() {
$.ajax('http://b.test.com:3000/test',{
type: 'PUT', //请求方式不是“get”时,需要在响应信息中设置“Access-Control-Allow-Methods”字段
headers: {test: 'ok'} //当设置了自定义头部时,需要在响应信息中设置“Access-Control-Allow-Headers”字段,否则请求被阻止。
}).done(function(data) {
alert(data);
})
}
</script>
</body>
</html>
在浏览器中输入a.test.com的域名,即可向b.test.com发送请求(反过来一样可以。)