【跨域】跨域的簡易實現和測試

前言

因爲本身平時只作作demo,並無遇到太多跨域問題,今天經過幾個樣例模擬實現了幾種跨域方式。原文地址 傳送門html

本文全部樣例靜態服務器基於nodejs實現,代碼親測可用。測試步驟以下:前端

1.爲了實現跨域訪問的效果,須要下載http-server 做爲一個服務器 npm install http-server。用來掛載靜態頁面 index.html 。(訪問http://127.0.0.1:8080 顯示index.html頁面)
2.運行node建立的靜態服務器node server (node搭建靜態服務向下翻)html5

JSONP跨域

JSONP實現跨域原理

說道跨域可能最早想到就時 jsonp ,實現原理爲:同源策略只限制瀏覽器的行爲而不限制js,因此能夠將請求寫到 script 標籤中。關鍵代碼以下:node

<script>
    function jsonpCallback(args){...}
</script>
<script src='http://127.0.0.1:3000?callback=jsonpCallback'></script>

前端發出跨域請求數據後,服務端去解析該請求:web

const data={...}
const callback = req.parse(req.url,true).query.callback
res.writeHead(200)

//最關鍵的一步,拼接回調函數和做爲函數參數的數據data
res.end(`${callback}(${JSON.stringfy(data)})`)

瀏覽器接收到服務端返回的響應,因爲發起請求的是script,至關於直接調用方法並傳入參數ajax

具體實現案例

(服務端代碼,node.js)npm

const url = require('url');

require('http').createServer((req, res) => {
    const data = {
        x: 10
    };
    const callback = url.parse(req.url, true).query.callback
    res.writeHead(200);
    //回調原頁面上函數處理返回結果
    res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, '127.0.0.1');
console.log('服務器已啓動...');

(前端)json

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            function jsonpCallback(data){
                alert('跨域成功')
            }   
        </script>
        <script src="http://127.0.0.1:3000/?callback=jsonpCallback"></script>
    </body>
</html>

JSONP解決Ajax跨域問題

若是是採用js原生,能夠參考傳送門segmentfault

CORS跨域

實現CORS跨域的思想爲:CORS通訊和Ajax同源請求沒有區別,關鍵在於服務端的配置。要想實現CORS通訊,服務端必需要設置一個自定義頭Access-Control-Origin:''來容許跨域訪問 後端

(樣例僅作了一個最簡單的GET請求demo服務端代碼)

require('http').createServer((req,res)=>{
    res.writeHead(200,{
        'Access-Control-Allow-Origin':'http://127.0.0.1:8080'
    })
    res.end('這是來自端口3000的信息,收好了~')
}).listen(3000,'127.0.0.1')

(前端代碼)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
    </body>
    <script>
        //CORS通訊和同源ajax通訊沒有區別,重點是子服務器端要設置能夠容許跨域的自定義頭
        const ajax = new XMLHttpRequest()
        ajax.open('post','http://127.0.0.1:3000',true) 
        ajax.onreadystatechange = function(){
            if(ajax.readyState===4){
                if(ajax.status>=200&&ajax.status<300||ajax.status===304){
                    alert(ajax.responseText)
                }
            }
        }
        ajax.send(null)
    </script>
</html>

cors實現跨域的優勢是不但能實現 GET , POST 等簡單請求,還能實現 PUT 等非簡單請求跨域

ServerProxy服務器代理

ServerProxy服務器代理實現跨域的核心思想是:將跨域請求操做發送給服務端,由服務端代爲請求,而後將請求結返回過來
這裏以獲取 CNode:Node.js專業中文社區 論壇上一些數據爲場景。如經過 https://cnodejs.org/api/v1/to...,當時由於不一樣域,因此你能夠將請求後端,讓其對該請求代爲轉發。

const url = require('url')
const http = require('http')
const https = require('https')

const server = http.createServer((req,res)=>{
    const path = url.parse(req.url).path.slice(1)
    if(path==='topics'){
        https.get('https://cnodejs.org/api/v1/topics', (resp) => {
            let data=''
            resp.on('data',chunk=>{
                data+=chunk
            })
            resp.on('end',()=>{
                res.writeHead(200,{
                    'Content-Type':'application/json;charset=utf-8'
                })
                res.end(data)
            })
        })
    }
}).listen(3000,'127.0.0.1')

console.log('服務器已啓動...');

postMessage

postMessage是HTML5新增的一項功能,postMessage() 方法容許來自不一樣源的腳本採用異步方式進行有限通訊能夠實現跨文本文檔,多窗口,跨域消息傳遞。
利用postMessage不能和服務端交換數據,只能在兩個窗口 <iframe> 之間交換數據

postMessage(data,origin)方法接收兩個參數
data:html5規範中提到該參數能夠是JavaScript的任意基本類型或可複製的對象.然而並非全部瀏覽器都作到了這點兒,部分瀏覽器只能處理字符串參數,因此咱們在傳遞參數的時候須要使用JSON.stringify()方法對對象參數序列化
oringin:字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略。這個參數是爲了安全考慮,postMessage()方法只會將message傳遞給指定窗口,固然若是願意也能夠建參數設置爲"*",這樣能夠傳遞給任意窗口,若是要指定和當前窗口同源的話設置爲"/"

建立一個postMsg.html,建立一個iframe。使用postMessage能夠向 http://127.0.0.1:8081 發送消息,而後監聽 message ,能夠得到其餘文檔發來的消息

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <iframe src="http://127.0.0.1:8081/recieve.html" style="display:none;"></iframe>
        <script>
            window.onload = function(){
                let targetOrigin='http://127.0.0.1:8081'
                window.frames[0].postMessage('我要給你發消息了..!',targetOrigin)
            }
            window.addEventListener('message',function(e){
                console.log('postMsg.html 接收到的消息',e.data)
            })
        </script>
    </body>
</html>

(建立recieve.html文件)

<!DOCTYPE html>
<html lang="en">
    <head>
        <title></title>
        <meta charset="UTF-8">
    </head>
    <body>
        <script>
            window.addEventListener('message',function(e){
                if(e.source!=window.parent){
                    return
                }
                let data = e.data
                console.log('test.html 接收到的消息:',data)
                parent.postMessage('我已經接收到消息了!',e.origin)
            })
        </script>
    </body>
</html>

安全性: postMessage 採用的是 雙向安全機制 。發送方發送數據時,會確認接收方的源,而監聽方監聽到 message 事件後,也能夠用 event.origin 判斷是否來自於正確可靠的發送方

webSocket實現跨域

websocket是一中全雙工通訊協議,該協議不實行同源政策,只要服務器支持,就能夠經過它進行跨源通訊
websocket的應用實例:https://segmentfault.com/a/11...

document.domain

對於主域相同跨子域的狀況,能夠經過設置 document.domain 來解決。具體作法是在 example.com/a.html 和 sub.example.com/b.html 兩個文件分別加上 document.domain = example.com 而後經過a.html 文件建立一個iframe,去控制iframe的 window,從而進行交互

相關文章
相關標籤/搜索