如何实现跨域?
跨域是個(gè)比較古老的命題了,歷史上跨域的實(shí)現(xiàn)手段有很多,我們現(xiàn)在主要介紹三種比較主流的跨域方案,其余的方案我們就不深入討論了,因?yàn)槭褂脠?chǎng)景很少,也沒必要記這么多奇技淫巧。
1. 最經(jīng)典的跨域方案jsonp
jsonp本質(zhì)上是一個(gè)Hack,它利用<script>標(biāo)簽不受同源策略限制的特性進(jìn)行跨域操作。
jsonp優(yōu)點(diǎn):
實(shí)現(xiàn)簡(jiǎn)單
兼容性非常好
jsonp的缺點(diǎn):
只支持get請(qǐng)求(因?yàn)?lt;script>標(biāo)簽只能get)
有安全性問(wèn)題,容易遭受xss攻擊
需要服務(wù)端配合jsonp進(jìn)行一定程度的改造
Jsonp的原理:
function JSONP({ url,params,callbackKey,callback }) {// 在參數(shù)里制定 callback 的名字params = params || {}params[callbackKey] = 'jsonpCallback'// 預(yù)留 callbackwindow.jsonpCallback = callback// 拼接參數(shù)字符串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)} })2. 最流行的跨域方案cors
cors是目前主流的跨域解決方案,跨域資源共享(CORS) 是一種機(jī)制,它使用額外的 HTTP 頭來(lái)告訴瀏覽器 讓運(yùn)行在一個(gè) origin (domain) 上的Web應(yīng)用被準(zhǔn)許訪問(wèn)來(lái)自不同源服務(wù)器上的指定的資源。當(dāng)一個(gè)資源從與該資源本身所在的服務(wù)器不同的域、協(xié)議或端口請(qǐng)求一個(gè)資源時(shí),資源會(huì)發(fā)起一個(gè)跨域 HTTP 請(qǐng)求。
如果你用express,可以這樣在后端設(shè)置
?
3. 最方便的跨域方案Nginx
在生產(chǎn)環(huán)境中建議用成熟的開源中間件解決問(wèn)題。
nginx是一款極其強(qiáng)大的web服務(wù)器,其優(yōu)點(diǎn)就是輕量級(jí)、啟動(dòng)快、高并發(fā)。
現(xiàn)在的新項(xiàng)目中nginx幾乎是首選,我們用node或者java開發(fā)的服務(wù)通常都需要經(jīng)過(guò)nginx的反向代理。
反向代理的原理很簡(jiǎn)單,即所有客戶端的請(qǐng)求都必須先經(jīng)過(guò)nginx的處理,nginx作為代理服務(wù)器再講請(qǐng)求轉(zhuǎn)發(fā)給node或者java服務(wù),這樣就規(guī)避了同源策略。
#進(jìn)程, 可更具cpu數(shù)量調(diào)整 worker_processes 1;events {#連接數(shù)worker_connections 1024; }http {include mime.types;default_type application/octet-stream;sendfile on;#連接超時(shí)時(shí)間,服務(wù)器會(huì)在這個(gè)時(shí)間過(guò)后關(guān)閉連接。keepalive_timeout 10;# gizp壓縮gzip on;# 直接請(qǐng)求nginx也是會(huì)報(bào)跨域錯(cuò)誤的這里設(shè)置允許跨域# 如果代理地址已經(jīng)允許跨域則不需要這些, 否則報(bào)錯(cuò)(雖然這樣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模塊中的一個(gè)子模塊,用來(lái)定義一個(gè)虛擬訪問(wèn)主機(jī)server {listen 80;server_name localhost;# 根路徑指到index.htmllocation / {root html;index index.html index.htm;}# localhost/api 的請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到192.168.0.103:8080location /api {rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前綴, 否則會(huì)出現(xiàn)404proxy_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; # 轉(zhuǎn)發(fā)地址}# 重定向錯(cuò)誤頁(yè)面到/50x.htmlerror_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}}其它跨域方案
HTML5 XMLHttpRequest 有一個(gè)API,postMessage()方法允許來(lái)自不同源的腳本采用異步方式進(jìn)行有限的通信,可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞。
WebSocket 是一種雙向通信協(xié)議,在建立連接之后,WebSocket 的 server 與 client 都能主動(dòng)向?qū)Ψ桨l(fā)送或接收數(shù)據(jù),連接建立好了之后 client 與 server 之間的雙向通信就與 HTTP 無(wú)關(guān)了,因此可以跨域。
window.name + iframe:window.name屬性值在不同的頁(yè)面(甚至不同域名)加載后依舊存在,并且可以支持非常長(zhǎng)的 name 值,我們可以利用這個(gè)特點(diǎn)進(jìn)行跨域。
location.hash + iframe:a.html欲與c.html跨域相互通信,通過(guò)中間頁(yè)b.html來(lái)實(shí)現(xiàn)。 三個(gè)頁(yè)面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問(wèn)來(lái)通信。
document.domain + iframe: 該方式只能用于二級(jí)域名相同的情況下,比如 a.test.com 和 b.test.com 適用于該方式,我們只需要給頁(yè)面添加 document.domain =‘test.com’ 表示二級(jí)域名都相同就可以實(shí)現(xiàn)跨域,兩個(gè)頁(yè)面都通過(guò)js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域,就實(shí)現(xiàn)了同域
總結(jié)
- 上一篇: 未知的软件异常0xc0000409解决办
- 下一篇: 视频压制参数设置详细说明(转)