天天看點

前後端互動 - ajax如何跨域

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如何跨域

結果證明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 ";
	})
           
前後端互動 - ajax如何跨域
(直接傳回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>
           

繼續閱讀