7.3 快速排序
首先我們要知道跨域是什麼,又為什麼要有跨域操作
跨域是什麼
跨域,是指瀏覽器不能執行其他網站的指令碼。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實施的安全限制。
好這裡我們提煉出兩個東西---1.同源策略:url首部的協議+域名+埠號必須一樣,一者不同即為跨域
2.安全限制(這也是為什麼需要跨域操作下一段介紹)
為什麼需要跨域操作/為啥需要同源策略/為什麼要限制ajax跨域(面試可能會這樣問)
這個和cookie的儲存原理有關(這裡不介紹cookie),在生活裡我們登入一個網站P(photoshop學習網站),然後他會存個通行證,下一次我們再上p站的時候
它是不是就自動登入了,我們用別的網站去請求登入p是不是就登入不上。
然後這個例子我們把它專業化一下下
1.客戶向p網站的伺服器傳送登入請求,攜帶賬號密碼資料
2.P網站的伺服器校驗賬號密碼正確後,返回響應並給本地添加了Cookie
3.之後客戶再次向A網站發起請求會自動帶上A網站儲存在本地的cookie
4.P網站的伺服器從cookie中獲取賬號密碼資料後,返回登陸成功介面。
假如ajax請求可以跨域,那我是不是可以在這個部落格裡寫一段js,使用ajax向你的學習網站發起登入請求,因為
很多人的電腦上會存有學習網站的cookie不需要輸入賬號密碼直接就自動登入了,再ajax回撥函式中解析了返回的資料,
我就能知道你學的是不是potoshop了。
所以才需要同源策略,為了使用者的資訊保安也必須限制ajax的跨域操作
ps:同源策略限制內容:(1)儲存內容:cookie,localStorage,sessionStorage,(2)DOM節點
(3)ajax請求,需注意ajax請求會發送出去,也會被返回,但會被瀏覽器攔截。
不被限制的有img link script
進入正題jsonp
我們現在已經知道了能夠不被同源限制的標籤有img link script 那我們該選擇哪個嘞?
當然是script,只有這兄弟和程式碼有關嘛
首先咱得整個伺服器出來用 node模擬一下
//服務端 const http =require("http");//匯入http模組 http.createServer( (req,res) => { let weather="四川 梅雨天";//客戶端要訪問的資料 res.writeHead(200,{ "Content-Type":"text/plain;charset=utf-8" });//防止亂碼,用jq的Ajax就不需要,Ajax會自動識別 res.write(weather); res.end(); }) .listen(3000);//3000埠
然後在客戶端寫<script src="http://localhost:3000",會得到一個型別錯誤,因為js沒法解析四川 梅雨天呀,這玩意兒都不是個語句,它笨解析不了
也就是說我們要在res.write拼接一條語句傳給客戶端於是乎
//服務端 const http =require("http"); http.createServer( (req,res) => { let weather="四川 梅雨天"; res.writeHead(200,{ "Content-Type":"text/plain;charset=utf-8" }); res.write(`("document.write(${weather}")`); res.end(); }) .listen(3000);
然後再在客戶端寫<script src="http://localhost:3000",就發現頁面上能打印出四川 梅雨天了,可是有個問題,我們的操作是不是寫死了?那咱就在
客戶端整個操作有關的函式唄
function show(w) { alert(w); } </script>
然後把伺服器的res.write(`("document.write(${weather}")`);改成res.write(`("show(${weather}")`);嗯~ o(* ̄▽ ̄*)o可是又有問題了我要是想改函式是不是要改兩個地方
可不可以把這個函式整成動態的?可以的我們把函式的資訊放到url的query裡
<script src="http://localhost:3000?callback=show"> /*這裡用callback接受函式資訊,又因為本來show就是回撥函式(相信大家體會出來了)所以用的callback命名,愛用啥都可以*/
那麼在伺服器咋個取得callbck嘞
onst http =require("http"); const url=require("url");//引入url模組 http.createServer( (req,res) => { var Url=url.parse(req.url,true); var callback=Url.query.callback;//大概意思從url取到callback let weather="四川 梅雨天"; res.writeHead(200,{ "Content-Type":"text/plain;charset=utf-8" }); res.write(`${callback}("${weather}")`); res.end(); }) .listen(3000);
然後這個問題也解決了,但我們平時點一個按鈕然後做跨域請求肯定不是這樣把script標籤寫在外面浪費記憶體不說,程式碼還不美觀
所以終極的程式碼來了
//客戶端程式碼 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>天氣預報</button> <script> let click=document.querySelector("button"); click.addEventListener("click",()=>{ let script=document.createElement("script"); script.src=`http://localhost:3000/?callback=show`; document.body.appendChild(script) });//對按鈕新增點選事件在body裡生產script function show(w) { alert(w); document.body.lastChild.remove();//對每次生成的script在結束後移除 } </script> </body> </html> //伺服器程式碼不變
好了以上就是jsonp的原理總結一下,(1)宣告一個回撥函式,其函式名(如show)當做引數值,要傳遞給跨域請求資料的伺服器,
函式形參為要獲取目標資料(伺服器返回的data)。
(2)建立一個<script>
標籤,把那個跨域的API資料介面地址,賦值給script的src,
還要在這個地址中向伺服器傳遞該函式名(可以通過問號傳參:?callback=show)。
(3)伺服器接收到請求後,需要進行特殊的處理:把傳遞進來的函式名和它需要給你的資料拼接成一個字串,
(4)最後伺服器把準備的資料通過HTTP協議返回給客戶端,客戶端再呼叫執行之前宣告的回撥函式(show),
對返回的資料進行操作
所以jsonp是一種思想每個人寫的jsonp可能都會不一樣,但終終極方案JQubiery裡ajax請求裡寫dataType:"jsonp",完事兒了,但思想還是要理解的。