第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);
});