ajax如何跨域
同源政策是指 協定、域名,端口号 都一緻
這是浏覽器的強制規定
ajax 能不能跨域
測試 ajax 能不能實作跨域(準備兩個後端)
為了測試友善所有的頁面都直接放在了 static 檔案夾下
後端伺服器的準備
- 負責準備資料的後端
const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
const koaBody = require("koa-body");
let app = new Koa();
let router = new Router();
app.use(koaBody({
multipart : true
}));
app.use(static(__dirname+"/static"));
router.get("/",async ctx =>{
// 測試資料,檢視路由是否加載成功
ctx.body = {
name:"Mr_Qin",
age:"24"
};
// ctx.render()
});
router.get("/getAjax",async ctx =>{
console.log("來自 4000 的資料");
// 服務端沒有傳回任何東西的話 也會報錯
ctx.body = " var a = 24 ";
})
app.use(router.routes());
app.listen(4000);
- 啟動服務的後端
const Koa = require("koa");
const Router = require("koa-router");
const static = require("koa-static");
const koaBody = require("koa-body");
let app = new Koa();
let router = new Router();
app.use(koaBody({
multipart : true
}));
app.use(static(__dirname+"/static"));
router.get("/",async ctx =>{
ctx.body = {
name:"Mr_Qin",
age:"24"
};
// ctx.render()
});
app.use(router.routes());
app.listen(3000);
前端頁面的準備
- 兩個終端都要運作,啟動服務
- 嘗試跨域時,ajax 下的 open 方法的第二個值設定為 跨域的路由
<button>擷取ajax</button>
<script>
// ajax 不能實作跨域 自身無法做到
document.querySelector("button").onclick = function(){
let xhr = new XMLHttpRequest();
// 嘗試 ajax 直接跨域
xhr.open("get","http://localhost:4000/getAjax",true);
xhr.onload = function(){
console.log(xhr.responseText)
}
xhr.send()
}
</script>

結果證明ajax 直接跨域會報錯,自身的功能不支援,無法做到跨域
jsonp 方式跨域
-
根本原理
利用 script / img 标簽 可以直接跨域通路的标簽的特性( 浏覽器不會限制這兩個标簽 )
可以跨域的标簽(測試)
- 前端頁面準備
<!-- 引入網絡連結 script 跨域通路可實作 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 引入網絡連結 img 跨域通路可實作 -->
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1586328014788&di=def29a76ad69feeba01313fe559644d0&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20190121%2Fc884227770e64b67b024d48a8b51daca.jpeg" alt="" >
<!-- 注意參數的寫法 字元串需要加符号 數字不需要 -->
<script src="http://localhost:4000/getAjax"></script>
<!-- jsonp 雛形 -->
<script>
// 輸出引入的 vue
console.log(Vue);
console.log(a);
</script>
- 後端伺服器準備( 端口号為4000的伺服器 )
router.get("/getAjax",async ctx =>{
console.log("來自 4000 的資料");
// 服務端沒有傳回任何東西的話 也會報錯
ctx.body = " var a = 24 ";
})
(直接傳回JS代碼)存在小問題
通常情況下後端傳回的資料會很雜,一系列的功能代碼
不可能像測試時的 ctx.body = "var a = 24 ",這麼簡單
那這樣複雜的情況就明顯不符合需求
- 前端頁面處理
document.querySelector("button").onclick = function(){
let port = 4000; // 這裡需要 前、後端 協調處理
let o = document.createElement("script");
o.src = `http://localhost:${port}/getAjax`;
document.querySelector("head").appendChild(o);
// console.log(a) // 報錯不會發現,原因:同步的問題直接加載過了
// 不會很推薦 解決方式存在一些問題 小功能可以使用
o.onload = function(){
console.log(a);
}
}
優化處理
處理方式,前端寫函數傳遞到後端,再由後端将函數攜帶參數後傳回
- 前端頁面處理
<button>點選擷取跨域資源</button>
<script>
function cbfn(res){
// 後端傳回的資料在這裡
console.log(res);
}
document.querySelector("button").onclick = function(){
let port = 4000; // 這裡需要 前、後端 協調處理
let o = document.createElement("script");
// 屬性名 叫 cb 還是 callback 需要和後端 溝通過好 雙方一緻
o.src = `http://localhost:${port}/getAjax?cb=cbfn`;
// cb 傳遞的是一個函數體 給後端
document.querySelector("head").appendChild(o);
}
</script>
- 後端伺服器處理
router.get("/getAjax",async ctx =>{
let obj = {
aname:"卡特琳娜",
sex:"女"
}
// 這裡的 cb 是和後端人員共同拟定的名字
let cb = ctx.query.cb; // 來自前端的 ?cb=cbfn
// 封裝的方法時 傳入的參數為同樣為 cb
console.log(cb);
// 将參數傳遞回前端
ctx.body = `${cb}(${JSON.stringify(obj)})`;
})
ajax 實作 jsonp
後端資料準備的伺服器不需要變
前端需要引入封裝好的 jsonp.js 檔案(這裡省略了)
<button>請求jsonp</button>
<!-- 引入封裝的方法 -->
<script src="jsonp.js"></script>
<script>
// 回調函數 負責 去後端接收資料 并傳回
function cbFn(res){
console.log(res)
}
// 封裝的功能中 存在 ajax
document.querySelector("button").onclick = function(){
// 和 jQuery 很像
ajax({
url:"http://localhost:4000/getAjax",
data:{
name:"Mr_Qin",
age:"25"
},
dataType:"jsonp",
jsonp:"cbFn",// 回調函數 => 後端修改為 ctx.query.cbFn
success:function(res){ // 成功後傳回的資料
console.log(res);
}
})
}
</script>