第3章:前端跨越原理及解决办法
3.1同源策略
- 同源策略(Same-Origin Policy) 最早由 Netscape 公司提出,是浏览器的一种安全策略。
浏览器就会处于安全问题,提出的同源策略。
(过去的钓鱼的网站,里面的东西和正常的网页一样,除了网址,,获取你的用户名,密码来
iframe可以嵌套网页,钓鱼网站,分辨不了账户名的真假,都会跳出登录成功。)
- 同源: 协议、域名、端口号 必 须完全相同。
- 违背同源策略就是跨域。
因为我们的服务器有多个,所以肯定会要跨域
3.2如何解决跨域
3.2.1 解决方案:JSONP
1) JSONP是什么?
JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求。
优点:兼容性很好。
2) JSONP怎么工作的?
在网页有一些标签天生具有跨域能力,比如:img link iframe script。
JSONP就是利用script标签的跨域能力来发送请求的。
3)JSONP的使用
1.动态的创建一个script标签
var script = document.createElement("script");
2.设置script的src,一定要设置回调函数
script.src = "http://localhost:3000/testAJAX?callback=abc";
function abc(data) {
alert(data.name);
};
3.将script添加到body中
document.body.appendChild(script);
4.服务器中路由的处理
router.get("/testAJAX" , function (req , res) {
console.log("收到请求");
var callback = req.query.callback;
var obj = {
name:"孙悟空",
age:18
}
res.send(callback+"("+JSON.stringify(obj)+")");
});
4) jQuery中的Jsonp
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">按钮</button>
<ul id="list"></ul>
<script type="text/javascript" src="./jquery-1.12.3.js"></script>
<script type="text/javascript">
window.onload = function () {
var btn =document.getElementById("btn");
btn.onclick = function () {
$.getJSON("http://api.douban.com/v2/movie/in_theaters?callback=?",function (data) {
console.log(data);
//获取所有的电影的条目
var subjects = data.subjects;
//遍历电影条目
for(var i=0 ; i<subjects.length ; i++){
$("#list").append("<li>"+
subjects[i].title+"<br />"+
"<img src=\""+subjects[i].images.large+"\" >"+
"</li>");
}
});
}
}
</script>
</body>
</html>
3…2.2 Jsonp案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">按钮</button>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
$('#btn').click(function () {
/*
JSONP:
跨域:进行同源策略的检查,浏览器的ajax引擎检查的。
跨域只有ajax请求可能产生,别的请求script、img、video是不会产生跨域的
原理:利用script天然可以跨域的特性进行跨域的
优点:兼容性极好
缺点:只能发GET请求
*/
// 1. 创建script标签
/*const script = document.createElement('script');
// 2. 设置script src属性,设置请求地址?查询字符串。请求方式默认是get
script.src = 'http://localhost:3000/ajax?name=jack&callback=fn';
// 3. 设置请求成功回调函数
window.fn = function (data) {
// 响应成功的数据
console.log(data);
};
// 4. 将script标签添加到页面上,才能生效
document.body.appendChild(script);*/
$.getJSON('http://localhost:3000/ajax?callback=?', function (data) {
// 响应成功的数据
console.log(data);
})
})
</script>
</body>
</html>
3.2.3 CORS
cors:abbr. 连续运行参考站(ko 儿 s )
- CORS是什么?
因为jsonp太麻烦,而且只能发get请求,所以:
CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持get和post请求。
- CORS怎么工作的?
CORS是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
- CORS的使用
主要是服务器端的设置:
router.get("/testAJAX" , function (req , res) {
//通过res来设置响应头,来允许跨域请求
//res.set(“Access-Control-Allow-Origin”,“http://127.0.0.1:3000”);
res.set(“Access-Control-Allow-Origin”,"*");
res.send(“testAJAX返回的响应”);
});
3.3.4 CORS案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">按钮</button>
<script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
/*
cors:
优点:能支持任意的请求方式
缺点:兼容性稍差
*/
$('#btn').click(function () {
// 发送ajax请求
$.get('http://localhost:3000/cors', {name: 'jack', age: 18}, function (data) {
console.log(data);
});
})
</script>
</body>
</html>
const express = require('express');
const app = express();
app.use(express.static('public'));
// 解析请求体参数:只能解析采用urlencoded编码
app.use(express.urlencoded({extended: true}));
// 解析请求体参数:只能解析采用json编码
app.use(express.json());
app.get('/ajax', (req, res) => {
// 函数名:fn
const { callback } = req.query;
const data = {name: 'tom', age: 55};
// 返回响应 fn({name: 'tom', age: 55}) callback(json)
res.send(`${callback}(${JSON.stringify(data)})`);
});
app.post('/ajax', (req, res) => {
console.log(req.body);
res.json({name: 'tom', age: 20});
});
app.get('/cors', (req, res) => {
// 设置响应头
const safeUrl = ['http://localhost:63342', 'https://www.baidu.com'];
// 允许所有地址跨域
// res.set('access-control-allow-origin', '*');
const url = req.headers.origin;
console.log(url);
if (safeUrl.includes(url)) {
// 允许单个地址跨域
res.set('access-control-allow-origin', url);
res.set('access-control-allow-headers', 'X-Juejin-Src,X-Juejin-Client,X-Juejin-Uid,X-Juejin-Token');
res.set('Access-Control-Allow-Credentials', true);
res.set('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, HEAD');
res.set('Access-Control-Max-Age', 86400);
}
/*
Access-Control-Allow-Credentials: true 允许预检请求
当请求方式是POST PUT DELETE,或者请求头中有特殊字段(X-Juejin-Src),这个时候浏览器会先发送一个预检请求(请求方式是options)
预检请求: 检查当前请求是否能进行跨域。 如果不行,就不在发请求了。 如果行,在发送真正的请求
Access-Control-Allow-Headers: X-Juejin-Src,X-Juejin-Client,X-Juejin-Uid,X-Juejin-Token
允许以上这些字段跨域跨域(如果请求头中的特殊字段不在包含范围,就不允许跨域)
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD
允许怎么样请求方式跨域跨域
Access-Control-Allow-Origin: https://juejin.im
允许哪些地址可以跨域
Access-Control-Max-Age: 86400
预检请求跨域缓存
*/
res.send('hello cors');
});
app.listen(3000, (err) => {
if (!err) console.log('服务器启动成功了~');
else console.log(err);
});