1.最經典的跨域方案jsonp
jsonp本質上是一個Hack,它利用<script>標簽不受同源策略限制的特性進行跨域操作。
jsonp優點:
實現簡單
兼容性非常好
jsonp的缺點:
只支持get請求(因為<script>標簽只能get)
有安全性問題,容易遭受xss攻擊
需要服務端配合jsonp進行一定程度的改造
<script type="text/javascript"> function JSONP({ url, params, callbackKey, callback }) { // 在參數里制定 callback 的名字 params = params || {} params[callbackKey] = 'jsonpCallback' // 預留 callback window.jsonpCallback = callback // 拼接參數字符串 const paramKeys = Object.keys(params) const paramString = paramKeys .map(key => `${key}=${params[key]}`) .join('&') // 插入 DOM 元素 const script = document.createElement('script') script.setAttribute('src', `${url}?${paramString}`) document.body.appendChild(script) } JSONP({ url: 'http://s.weibo.com/ajax/jsonp/suggestion', params: { key: 'test', }, callbackKey: '_cb', callback(result) { console.log(result.data) } }) </script>
2.最流行的跨域方案cors
cors是目前主流的跨域解決方案,跨域資源共享(CORS) 是一種機制,它使用額外的 HTTP 頭來告訴瀏覽器
讓運行在一個 origin (domain) 上的Web應用被准許訪問來自不同源服務器上的指定的資源。
當一個資源從與該資源本身所在的服務器不同的域、協議或端口請求一個資源時,資源會發起一個跨域 HTTP 請求。
如果你用express,可以這樣在后端設置
<script type="text/javascript"> //CORS middleware var allowCrossDomain = function(req, res, next) { res.header('Access-Control-Allow-Origin', 'http://example.com'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); } //... app.configure(function() { app.use(express.bodyParser()); app.use(express.cookieParser()); app.use(express.session({ secret: 'cool beans' })); app.use(express.methodOverride()); app.use(allowCrossDomain); app.use(app.router); app.use(express.static(__dirname + '/public')); }); </script>
3.最方便的跨域方案Nginx
nginx是一款極其強大的web服務器,其優點就是輕量級、啟動快、高並發。
現在的新項目中nginx幾乎是首選,我們用node或者java開發的服務通常都需要經過nginx的反向代理。
反向代理的原理很簡單,即所有客戶端的請求都必須先經過nginx的處理,nginx作為代理服務器再講請求轉發給node或者java服務,這樣就規避了同源策略。
<script type="text/javascript"> #進程, 可更具cpu數量調整 worker_processes 1; events { #連接數 worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; #連接超時時間,服務器會在這個時間過后關閉連接。 keepalive_timeout 10; # gizp壓縮 gzip on; # 直接請求nginx也是會報跨域錯誤的這里設置允許跨域 # 如果代理地址已經允許跨域則不需要這些, 否則報錯(雖然這樣nginx跨域就沒意義了) add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; # srever模塊配置是http模塊中的一個子模塊,用來定義一個虛擬訪問主機 server { listen 80; server_name localhost; # 根路徑指到index.html location / { root html; index index.html index.htm; } # localhost/api 的請求會被轉發到192.168.0.103:8080 location /api { rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前綴, 否則會出現404 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://192.168.0.103:8080; # 轉發地址 } # 重定向錯誤頁面到/50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } </script>
4.其它跨域方案
HTML5 XMLHttpRequest 有一個API,postMessage()方法允許來自不同源的腳本采用異步方式進行有限的通信,可以實現跨文本檔、多窗口、跨域消息傳遞。
WebSocket 是一種雙向通信協議,在建立連接之后,WebSocket 的 server 與 client 都能主動向對方發送或接收數據,連接建立好了之后 client 與 server 之間的雙向通信就與 HTTP 無關了,因此可以跨域。
window.name + iframe:window.name屬性值在不同的頁面(甚至不同域名)加載后依舊存在,並且可以支持非常長的 name 值,我們可以利用這個特點進行跨域。
location.hash + iframe:a.html欲與c.html跨域相互通信,通過中間頁b.html來實現。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通信。
document.domain + iframe: 該方式只能用於二級域名相同的情況下,比如 a.test.com 和 b.test.com 適用於該方式,我們只需要給頁面添加 document.domain ='test.com' 表示二級域名都相同就可以實現跨域,兩個頁面都通過js強制設置document.domain為基礎主域,就實現了同域。
6.其余方案來源於九種跨域方式