1. 程式人生 > >跨域詳解及其常見的解決方式

跨域詳解及其常見的解決方式

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.comcookieevil.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

    原理:WebSocketHTML5的協議,可以讓瀏覽器與服務器之間建立一個全雙工、雙向通信。當瀏覽器使用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 發送給客戶端的數據
    })

跨域詳解及其常見的解決方式