最近想用node作为后台抛出接口,前端页面去请求接口的时候报错了,发现是跨域的问题。为什么会出现跨域问题呢?我们就需要了解什么是浏览器的同源策略。
什么是浏览器的同源策略,为什么要同源策略
同源策略简单来说就是三同,同协议、同域名、同端口。个域内的脚本仅仅具有本域内的权限,可以理解为本域脚本只能读写本域内的资源,而无法访问其它域的资源。这种安全限制称为同源策略,有同源策略的原因就在于为了提升浏览器的安全性,但是,我们都知道安全性和方便性是成反比的,有了高的安全性必定给我们的操作带来低效,牺牲了Web拓展上的灵活性,现代浏览器在安全性和可用性之间选择了一个平衡点。在遵循同源策略的基础上,选择性地为同源策略“开放了后门”。例如img、script 、style等标签,都允许垮域引用资源,严格说这都是不符合同源要求的。
JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤为重要。根据这个策略,在souhu.com下的页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不同的子域名之间的页面也不能通过JavaScript代码互相访问。对于Ajax的影响在于,通过XMLHttpRequest实现的Ajax请求,不能向不同的域提交请求,例如,在you.example.com下的页面,不能向me.example.com提交Ajax请求,等等。
举例说明
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.baidu.com/a.js http://www.baidu.com/b.js |
同一域名 | 允许 |
http://www.baidu.com/map/a.js http://www.baidu.com/tieba/b.js |
同一域名不同文件夹下 | 允许 |
http://www.baidu.com:8000/a.js http://www.baidu.com/b.js |
同一域名不同端口 | 不允许 |
http://www.baidu.com/a.js https://www.baidu.com/b.js |
同一域名不同协议 | 不允许 |
http://www.baidu.com/a.js http://75.32.68.45/b.js |
域名和域名对应ip | 不允许 |
http://www.baidu.com/a.js http://query.baidu.com/b.js |
主域相同,子域不同 | 不允许 |
http://www.baidu.com/a.js http://www.google.com/b.js |
不同域名 | 不允许 |
为什么浏览器要实现同源限制?我们举例说明:
比如一个黑客,他利用iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名和密码登录时,如果没有同源限制,他的页面就可以通过javascript读取到你的表单中输入的内容,这样用户名和密码就轻松到手了。又比如你登录了淘宝,同时浏览了恶意网站,如果没有同源限制,该恶意 网站就可以构造AJAX请求频繁在淘宝发广告帖.
这是前端页面显示的错误
//前端页面报错内容
Failed to load http://localhost:3000/users/login: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
//服务端错误方法
// node登录接口,文件地址routes/users.js
router.post('/login',function (req, res, next) {
// 打印post请求的数据内容
console.log(req.body);
console.log(req.body.username);
console.log(req.body.password);
if (req.body.username == "shuah" && req.body.password == "123456") {
res.end(JSON.stringify(dataSuccess));
} else {
res.end(JSON.stringify(dataError));
}
});
//前端数据请求
//引用jquery.js
var data ={
username:'shuah',
password:'123456'
}
$.ajax({
url: "http://localhost:3000/users/login",
type: "POST",
headers:{
"Conten-Type":"http://localhost:3000/users/login"
},
data: JSON.stringify(data),
dataType:"json",
success: function(data){
console.info("success.");
console.log(data)
}
})
总结了两个解决node跨域的方法。
- 简单粗暴,但是任何页面都可以请求,不安全。
//在每个方法的头部加入
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
// login 方法修改为
router.post('/login',function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1');
res.header("Content-Type", "application/json;charset=utf-8");
// 打印post请求的数据内容
console.log(req.body);
console.log(req.body.username);
console.log(req.body.password);
if (req.body.username == "shuah" && req.body.password == "123456") {
res.end(JSON.stringify(dataSuccess));
} else {
res.end(JSON.stringify(dataError));
}
});
//前端页面
$.ajax({
url: "http://localhost:3000/users/login",
type: "POST",
data:data,
dataType:"json",
success: function(data){
console.info("success.");
console.log(data)
}
})
2.引入 cors 安全,自定义
npm install cors
cors的githbu地址,里面有更加多的方法 https://github.com/expressjs/cors
//相对与上一个方法,这个不用每个方法都添加请求头
//在app.js里面修改
var cors = require('cors')
app.use(cors())
//自定义设置
//在app.js里面修改,只有http://localhost可以访问请求,其他都为跨域,安全,需要启动一个本地服务
var cors = require('cors')
app.use(cors({
origin:['http://localhost'],
methods:['GET','POST'],
alloweHeaders:['Conten-Type', 'Authorization']
}));
//前端页面
$.ajax({
url: "http://localhost:3000/users/login",
type: "POST",
data:data,
dataType:"json",
success: function(data){
console.info("success.");
console.log(data)
}
})