【小哥哥, 跨域要不要了解下】CORS 基礎篇

圈圈Dei圈發表於2018-12-07

系列文章:

前一篇文章中, 我們一起學習了第一種跨域處理方案 JSONP. 這種方法相對比較原始, 優點是相容性好, 就連現代前端沒怎麼聽說過的 IE 6 上跑起來都是妥妥的. 然鵝, 它也就這一點優點了. 其缺點有: 只支援 GET 請求, 配置繁瑣(前後端都需要調整程式碼), 在 window 上註冊各種回撥函式, 開發體驗差....

2018-12-07-10-07-21

CORS

由於 JSONP 的方案存在諸多缺點且老舊, 這裡我們一起學習一種比較現代的跨域問題解決方案---CORS

相容性

從 mdn 官網粘來的相容性列表如下:

2018-12-07-10-25-52

ie 10 都可以跑, 足以滿足現代前端開發者的需求了.

概念 ?

概念性的東西在這兒 MDN 偶爾需要梯子, 自備哈.

搭建跨域的環境

我們先建立一個跨域的環境, 程式碼基於我們 jsonp 時候的示例專案 cross-domain, 首先, 在 fe 和 be 目錄下建立 cors 目錄. 其次, 分別新增 index.htmlindex.js. 修改以後的專案目錄如下圖.

2018-12-07-14-26-54

編寫前端程式碼 fe/cors/index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>CORS 實現跨域</title>
</head>
<body>
    <h3>CORS 實現跨域</h3>

    <script>
        var xhr = new XMLHttpRequest()
        xhr.open('GET', 'http://localhost:8888')
        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4 && xhr.status === 200) {
                console.log(xhr.responseText)
            }
        }
        xhr.send()
    </script>
</body>
</html>
複製程式碼

一個灰常簡單的 ajax 請求, 有木有.

後端程式碼 be/cors/index.js

const http = require('http');

const PORT = 8888;

// 建立一個 http 服務
const server = http.createServer((request, response) => {
  response.end("{name: 'quanquan', friend: 'guiling'}");
});

// 啟動服務, 監聽埠
server.listen(PORT, () => {
  console.log('服務啟動成功, 正在監聽: ', PORT);
});
複製程式碼

此時的專案程式碼

找點苗頭

程式碼環境準備完成後

  • 首先啟動後端程式碼 node ./be/cors/index.js
  • 其次啟動前端 web 容器 live-server ./fe/cors
  • 開啟瀏覽器, 訪問 http://localhost:8080/
  • 開啟控制檯, 切換到 Console tab
  • 重新整理瀏覽器

2018-12-07-16-47-05
我們細細分析這個熟悉的報錯, 前一段告訴我們我們的請求被 block 了. 後邊居然直接告訴我們解決方案了, 方案了 'Access-Control-Allow-Origin' header is present on the requested resource., 這麼明顯的暗示, 難道我們就不試試???
2018-12-07-17-27-44

響應頭新增 Access-Control-Allow-Origin

針對瀏覽器的報錯, 我們分析出他是要我們在響應頭上新增Access-Control-Allow-Origin這個欄位, 那麼我們修改我們的後端程式碼.

const http = require('http');

const PORT = 8888;

// 建立一個 http 服務
const server = http.createServer((request, response) => {
  response.setHeader('Access-Control-Allow-Origin', '*');
  response.end("{name: 'quanquan', friend: 'guiling'}");
});

// 啟動服務, 監聽埠
server.listen(PORT, () => {
  console.log('服務啟動成功, 正在監聽: ', PORT);
});
複製程式碼

改動後的程式碼.

巨大的 PS: 修改過後端程式碼以後, 一定要重啟 node 服務

瀏覽器重新整理一下, 我了個乖乖. 好了 ?

2018-12-07-17-33-48

開心過後, 我們想一下, jsonp 的缺點是隻能支援 GET 請求, 作為現代的跨域請求方式. cors 能不能支援其他的請求方式呢?

其他請求方式的支援

作為現代的跨域問題解決方案, 應該是能解決多種請求方式的. 光說不練假把式. 我們們試試 ?

改動前端程式碼

// 改動前
xhr.open('GET', 'http://localhost:8888')
// 改動後
xhr.open('POST', 'http://localhost:8888')
複製程式碼

修改後程式碼來瀏覽器上看一下?

2018-12-07-18-22-46

木有任何問題, 返回的資料順利的列印. 沒有任何的報錯.

趁著興頭試試PUT請求

再次改動前端程式碼

// 改動前
xhr.open('POST', 'http://localhost:8888')
// 改動後
xhr.open('PUT', 'http://localhost:8888')
複製程式碼

修改後程式碼來瀏覽器上看一下?

2018-12-07-18-25-55

哎呀我滴媽? 很眼熟的錯誤, 但是不要認錯人哈, 這次的報錯和之前的報錯長的很像, 但是關鍵詞不一樣了. 根據之前的經驗, 後端新增 Access-Control-Allow-Methods 響應頭應該好使.

後端程式碼

const http = require('http');

const PORT = 8888;

// 建立一個 http 服務
const server = http.createServer((request, response) => {
  response.setHeader('Access-Control-Allow-Origin', '*');
  response.setHeader('Access-Control-Allow-Methods', 'PUT');
  response.end("{name: 'quanquan', friend: 'guiling'}");
});

// 啟動服務, 監聽埠
server.listen(PORT, () => {
  console.log('服務啟動成功, 正在監聽: ', PORT);
});
複製程式碼

修改後程式碼來瀏覽器上看一下?

2018-12-07-18-32-14

成功了 ?

2018-12-07-18-33-45

其他的 http 方法和 PUT 方法處理的方式是一樣的. 舉一反三即可.

後端說, 你的請求要加一個 token 呀

既然是現代的開發, 那麼會話的管理一般是會用 jwt(後續可能會寫相關的文章), jwt 一個閃耀的標誌就是請求頭新增了 jwt token. 明人不說暗話.

2018-12-07-18-39-07

修改前端程式碼:

// 新增了一行
xhr.setRequestHeader('token', 'quanquanbunengshuo')
複製程式碼

修改後程式碼來瀏覽器上看一下?

2018-12-07-18-43-04

相信大家已經摸清了我的套路, 閒話不扯.

後端程式碼

// 新增了一行
response.setHeader('Access-Control-Allow-Headers', 'token');
複製程式碼

修改後程式碼來瀏覽器上看一下?

2018-12-07-18-45-14

目前為止, 跨域請求成功了, 請求方式相容了, 自定義請求頭好使了. 是不是大吉大利, 可以吃雞了呢?

致, 被打入冷宮的 Network tab

我們自始至終都在檢視瀏覽器的 Console tab, 作為一個通訊性質的文章, 不看一下 Network 明顯有點說不過去辣.

2018-12-07-18-50-42

既然存在, 那肯定是要看看的, 我們把 tab 切換到 Network.

2018-12-07-18-52-58

哎呦喂? 兩個請求, 一個 OPTIONS 一個 PUT, 這是什麼鬼?

下集預告: 剛剛看到了 Network 就出現了血案. 當然如果僅僅是停留在會用 CORS 實現跨域上, 到目前為止已經沒有什麼問題了, 用來面試也是槓槓滴. 下一步, 我們一起探討 CORS 條件下, 預檢請求Cookie 攜帶那些事兒. 週五碼字感覺好累...... 約小姐姐去辣 ?

9150e4e5ly1fkhkg77t1mg204603w12l

相關文章