跨域
跨域
定義
跨域是指一個域下的文件或指令碼試圖去請求另一個域下的資源
同源策略
如果兩個頁面的協議,埠(如果有指定)和域名都相同,則兩個頁面具有相同的源.瀏覽器出於安全方面的考慮,只允許與本域下的介面互動。不同源的客戶端指令碼在沒有明確授權的情況下,不能讀寫對方的資源。
跨域的實現形式
1 通過jsonp跨域 2 document.domain + iframe跨域 3 location.hash + iframe 4 window.name + iframe跨域 5 postMessage跨域 6 跨域資源共享(CORS) 7 nginx代理跨域 8 nodejs中介軟體代理跨域 9 Socket/">WebSocket協議跨域
JSONP
HTML 中 script 標籤可以載入其他域下的js,比如我們經常引入一個其他域下線上cdn的jQuery。那如何利用這個特性實現從其他域下獲取資料?
如果這樣寫:
<script src="http://api.jirengu.com/weather.php"></script>
這時會向天氣介面傳送請求獲取資料,獲取資料後做為 js 來執行。 但這裡有個問題, 資料是 JSON 格式的資料,若直接作為 JS 來執行,那可以這樣寫:
<script src="http://api.jirengu.com/weather.php?callback=showData"></script>
這個請求到達後端後,後端會去解析callback這個引數獲取到字串showData,在傳送資料做如下處理:
之前後端返回資料: {"city": "hangzhou", "weather": "晴天"} 現在後端返回資料: showData({"city": "hangzhou", "weather": "晴天"}) 前端script標籤在載入資料後會把 「showData({“city”: “hangzhou”, “weather”: “晴天”})」作為 js 來執行,這實際上就是呼叫showData這個函式,同時引數是 {“city”: “hangzhou”, “weather”: “晴天”}。 使用者只需要在載入提前在頁面定義好showData這個全域性函式,在函式內部處理引數即可。
function showData(ret){ console.log(ret); }
將此函式加入到JS中即可。
總結
JSONP是通過 script 標籤載入資料的方式去獲取資料當做 JS 程式碼來執行,提前在頁面上宣告一個函式,函式名通過介面傳參的方式傳給後臺,後臺解析到函式名後在原始資料上「包裹」這個函式名,傳送給前端。換句話說,JSONP 需要對應介面的後端的配合才能實現 。
例子
index.html
<!DOCTYPE html> <html> <body> <div class="container"> <ul class="news"> </ul> <button class="show">show news</button> </div> <script> $('.show').addEventListener('click', function(){ var script = document.createElement('script'); script.src = 'http://127.0.0.1:8080/getNews?callback=appendHtml'; document.head.appendChild(script); document.head.removeChild(script); }) function appendHtml(news){ var html = ''; for( var i=0; i<news.length; i++){ html += '<li>' + news[i] + '</li>'; } console.log(html); $('.news').innerHTML = html; } function $(id){ return document.querySelector(id); } </script> </html>
server.js
var http = require('http') var fs = require('fs') var path = require('path') var url = require('url') http.createServer(function(req, res){ var pathObj = url.parse(req.url, true) switch (pathObj.pathname) { case '/getNews': var news = [ "第11日前瞻:中國衝擊4金 博爾特再戰200米羽球", "正直播柴飈/洪煒出戰 男雙力爭會師決賽", "女排將死磕巴西!郎平安排男陪練模仿對方核心" ] res.setHeader('Content-Type','text/json; charset=utf-8') if(pathObj.query.callback){ res.end(pathObj.query.callback + '(' + JSON.stringify(news) + ')') }else{ res.end(JSON.stringify(news)) } break; default: fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){ if(e){ res.writeHead(404, 'not found') res.end('<h1>404 Not Found</h1>') }else{ res.end(data) } }) } }).listen(8080)
終端除錯

