跨域詳解及其常見的解決方式
阿新 • • 發佈:2019-03-17
javascrip thead creates 二級域名 www. -c process scrip 2.7
跨域是什麽
跨域是一個域下的網頁去請求另一個域下的資源。嚴格點來說就是兩個域的協議、域名、端口任何一個不同時,都會被當作跨域。當跨域訪問資源時,會受到瀏覽器的安全限制,詳細的情況可以看下表:
URL | 說明 | 是否允許通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js |
同一域名 | 允許 |
http://www.a.com/a/a.js http://www.a.com/b/b.js |
同一域名,不同文件夾 | 允許 |
http://www.a.com:3000/a.js http://www.a.com/b.js | 同一域名,不同端口 | 不允許 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名,不同協議 | 不允許 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名對應IP | 不允許 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不同 | 不允許 |
http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二級域名(同上) | 不允許 |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不同域名 | 不允許 |
為什麽限制跨域訪問資源
瀏覽器限制跨域訪問資源是一種安全策略,可以預防某些惡意行為。瀏覽器在每次發起請求時都會帶上cookie
,試想下,如果沒有這總安全策略,evil.com
也會拿到用戶在secure.com
的cookie
,evil.com
利用cookie
裏的信息登錄用戶的賬號,這樣用戶的數據就被泄露了。跨域限制就是為了避免這種情況的發生。
跨域資源的幾種訪問方式
jsonp
原理:
jsonp
之所以能夠實現跨域資源的訪問,是因為<script>
標簽不受瀏覽器同源策略的限制,使用時將src
屬性指定一個跨域URL
,服務器在收到請求後,將數據放到指定的callback
裏傳回來。實現:
優缺點:前端部分: function fetchjsonp(res) { console.log(res) // 可以獲得服務端的數據,{data: "json data"} } const script = document.createElement('script') script.src = 'http://127.0.0.1:8080?callback=fetchjsonp' document.head.appendChild(script) 服務端: const http = require('http'); const hostname = '127.0.0.1'; const port = 8080; const server = http.createServer((req, res) => { if (~req.url.indexOf('?callback')) { // 簡單處理 JSONP 跨域的時候 const obj = { "data": 'json data', } const callback = req.url.split('callback=')[1] const jsonData = callback + `(${JSON.stringify(obj)})` res.end(jsonData) // 這裏最終返回前端的是相當於調用函數 callback({json}) } else { // 非跨域的時候 res.statusCode = 200 res.setHeader('Content-Type', 'text/plain') res.end('not jsonp\n') } }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
jsonp
優點是兼容性好,支持低版本的瀏覽器跨域訪問。缺點是只支持get
請求,不容易判斷請求是否失敗。CORS
原理:CORS(cross-origin-resource-sharing)跨域資源共享,其思想是使用自定義的
HTTP
頭部,讓瀏覽器域服務器進行溝通,從而決定請求或響應是成功還是失敗。服務器端一般在Access-Control-Allow-Origin
中指定對應的域,當瀏覽器訪問對應的資源。
實現:
優缺點:優點是支持所有的前端部分: axios.get('http://127.0.0.1:8080/').then(res => { console.log(res) // data from cors }) 服務端: const http = require('http') const hostname = '127.0.0.1' const port = 8080 const server = http.createServer((req, res) => { res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3000') // 設置請求源 res.setHeader('Access-Control-Allow-Methods', 'get') // 設置請求方法 res.end('data from cors') }) server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`) })
HTTP
請求方法,缺點是不支持老的瀏覽器;使用代理
原理:上面我們已經說了,瀏覽器的跨域限制是發生在瀏覽器裏的,服務器端是沒有的,所以可以使用服務器代理請求其他域的資源,然後在返回給客戶端。
實現:比如說瀏覽器直接訪問http://127.0.0.1:8080
會被限制,那麽我們可以使用node作代理,來獲取http://127.0.0.1:8080
返回的資源。
前端部分: axios.get(‘http://127.0.0.1:8000/‘).then(res => { console.log(res) }) node代理: const express = require(‘express‘) const request = require(‘request‘) const app = express() app.use(‘/‘, function (req, res) { res.set(‘Access-Control-Allow-Origin‘, ‘*‘) const url = ‘http://127.0.0.1:8080‘ // 代理的URL req.pipe(request(url)).pipe(res) }) app.listen(process.env.PORT || 8000)
使用WebSocket
原理:
WebSocket
是HTML5
的協議,可以讓瀏覽器與服務器之間建立一個全雙工、雙向通信。當瀏覽器使用websocket
與服務器建立連接後,HTTP
協議會變成websocket
協議,websocket
協議是不受同源策略限制的,所以可以實現跨域請求資源;實現:
前端部分: const ws = new WebSocket("ws://127.0.0.1:8080") ws.onopen = function (e) { console.log('Connection to server opened') } ws.onmessage = function (event) { console.log('Client received a message: ', event.data) // 客戶端接受的數據在 event.data 中 } 服務端: const WebSocketServer = require('ws').Server const ws = new WebSocketServer({ port: 8080 }) ws.on('connection', (ws) => { ws.send('hello websocket') // websocket 發送給客戶端的數據 })
跨域詳解及其常見的解決方式