跨域是一個域下的網頁去請求另外一個域下的資源。嚴格點來講就是兩個域的協議、域名、端口任何一個不一樣時,都會被看成跨域。當跨域訪問資源時,會受到瀏覽器的安全限制,詳細的狀況能夠看下錶:javascript
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
之因此可以實現跨域資源的訪問,是由於<script>
標籤不受瀏覽器同源策略的限制,使用時將src
屬性指定一個跨域URL
,服務器在收到請求後,將數據放到指定的callback
裏傳回來。java
實現:node
前端部分: 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(cross-origin-resource-sharing)跨域資源共享,其思想是使用自定義的HTTP
頭部,讓瀏覽器域服務器進行溝通,從而決定請求或響應是成功仍是失敗。服務器端通常在Access-Control-Allow-Origin
中指定對應的域,當瀏覽器訪問對應的資源。
實現:ios
前端部分: 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
請求方法,缺點是不支持老的瀏覽器;原理:上面咱們已經說了,瀏覽器的跨域限制是發生在瀏覽器裏的,服務器端是沒有的,因此可使用服務器代理請求其餘域的資源,而後在返回給客戶端。web
實現:好比說瀏覽器直接訪問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
是HTML5
的協議,可讓瀏覽器與服務器之間創建一個全雙工、雙向通訊。當瀏覽器使用websocket
與服務器創建鏈接後,HTTP
協議會變成websocket
協議,websocket
協議是不受同源策略限制的,因此能夠實現跨域請求資源;express
實現:json
前端部分: 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 發送給客戶端的數據 })