詳解使用Node.js怎麼處理CORS

2020-10-28 21:00:50

視訊教學推薦:

介紹

在本文中,我們將研究怎樣用 Express 設定 CORS 以及根據需要客製化 CORS 中介軟體。

什麼是CORS

CORS 是「跨域資源共用」的簡寫。它是一種允許或限制向 Web 伺服器上請求資源的機制,具體取決於進行 HTTP 請求的位置。

這種策略用於保護特定 Web 伺服器免受其他網站或域的存取。只有允許的域才能存取伺服器中的檔案,例如樣式表、影象或指令碼等。

假設你當前使用的是 http://example.com/page1,並且你參照的是來自 http://image.com/myimage.jpg 的圖片,那麼除非 http://image.com 允許與 http://example.com 進行跨域共用,否則將無法獲取該影象。

每個 HTTP 請求頭中都有一個名為 origin 的頭。它定義了域請求的來源。可以用這個頭的資訊來限制參照你伺服器上的資源。

預設來自任何其他來源的請求都會受到瀏覽器的限制。

例如當開發時如果用的是 React 或 Vue 這類的前端庫,則前端應用將執行在 http://localhost:3000 上,同時,你的 Express 伺服器可能正在其他埠上執行,例如 http://localhost:2020。這時就需要在這些伺服器之間允許 CORS。

如果你在瀏覽器控制檯中看到下圖這類的錯誤。問題可能出在 CORS 限制上:

1.png

如果我們需要提供公共 API 並希望控制對某些資源的存取和使用方式時,CORS 能夠發揮很大的作用。

另外,如果想在其他網頁上使用自己的 API 或檔案,也可以簡單地將 CORS 設定為允許自己參照,同時把其他人拒之門外。

用 Express 設定 CORS

首先建立一個新的專案,並建立目錄結構,然後使用預設設定執行 npm init

$ mkdir myapp
$ cd myapp
$ npm init -y

接下來安裝所需的模組。我們將使用 expresscors 中介軟體:

$ npm i --save express
$ npm i --save cors

然後,開始建立一個簡單的有兩個路由的 Web 程式,用來演示 CORS 的工作原理。

首先建立一個名為 index.js 的檔案,用來充當 Web 伺服器,並實現幾個請求處理常式:

const express = require('express');
const cors = require('cors');

const app = express();

app.get('/', (req, res) => {
    res.json({
        message: 'Hello World'
    });
});

app.get('/:name', (req, res) => {
    let name = req.params.name;

    res.json({
        message: `Hello ${name}`
    });
});

app.listen(2020, () => {
    console.log('server is listening on port 2020');
});

執行伺服器:

$ node index.js

存取 http://localhost:2020/ 伺服器應該返回 JSON 訊息:

{
  "message": "Hello World"
}

存取 http://localhost:2020/something 應該能夠看到:

{
  "message": "Hello something"
}

啟用所有CORS請求

如果想為所有的請求啟用 CORS,可以在設定路由之前簡單地使用 cors 中介軟體:

const express = require('express');
const cors = require('cors');

const app = express();

app.use(cors())

......

如果需要,這會允許在網路上的任何位置存取所有路由。所以在本例中,每個域都可以存取兩條路由。

例如,如果我們的伺服器在 http://www.example.com 上執行並提供諸如圖片之類的內容,則我們允許 http://www.differentdomain.com 之類的其他域從 http://www.example.com 進行引。

因此 http://www.differentdomain.com 上的網頁可以將我們的域用作影象的來源:

<img src="http://www.example.com/img/cat.jpg">

為單個路由啟用 CORS

如果只需要其中某一個路由,可以在某個路由中將 cors 設定為中介軟體:

app.get('/', cors(), (req, res) => {
    res.json({
        message: 'Hello World'
    });
});

這會允許任何域存取特定的路由。在當前的情況下,其他域都只能存取 / 路由。僅在與 API(在本例中為http://localhost:2020)的相同域中發起的請求才能存取 /:name 路由。

如果嘗試另一個來源傳送請求到 / 路徑將會成功,並且會收到 Hello World 作為響應:

fetch('http://localhost:2020/')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(err => console.error(err));

執行上面的程式碼,會看到來自伺服器的響應已成功輸出到控制檯:

{
    message: 'Hello World'
}

如果存取除根路徑以外的其他路徑,例如 http://localhost:2020/namehttp://localhost:2020/img/cat.png,則此請求將會被瀏覽器阻止:

fetch('http://localhost:2020/name/janith')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

如果在其他 Web 應用中執行程式碼,應該看到以下錯誤:

2.png

用選項設定CORS

還可以用自定義選項來設定 CORS。可以根據需要設定允許的 HTTP 方法,例如 GETPOST

下面是通過 CORS 選項允許單個域存取的方法:

var corsOptions = {
    origin: 'http://localhost:8080',
    optionsSuccessStatus: 200 // For legacy browser support
}

app.use(cors(corsOptions));

如果你在源中設定域名-伺服器將允許來自已設定域的CORS。因此,在我們的例子中,可以從 http://localhost:8080 存取該API,並禁止其他域使用。

如果傳送一個 GET 請求,則任何路徑都應該可以存取,因為這些選項是在應用在程式級別上的。

執行下面的程式碼將請求從 http://localhost:8080 傳送到 http://localhost:2020

//
fetch('http://localhost:2020/')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

//
fetch('http://localhost:2020/name/janith')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => console.error(err));

可以看到被允許從該程式和域中獲取資訊。

還可以根據需要設定允許的 HTTP 方法:

var corsOptions = {
    origin: 'http://localhost:8080',
    optionsSuccessStatus: 200 // 對於舊版瀏覽器的支援
    methods: "GET, PUT"
}

app.use(cors(corsOptions));

如果從 http://localhost:8080 傳送POST請求,則瀏覽器將會阻止它,因為僅支援 GET 和 PUT:

fetch('http://localhost:2020', {
  method: 'POST',
  body: JSON.stringify({name: "janith"}),
})
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.error(err));

用函數設定動態 CORS 源

如果設定不滿足你的要求,也可以建立函數來客製化 CORS。

例如假設要允許 http://something.com 和 http://example.com 對 .jpg 檔案進行CORS共用:

const allowlist = ['http://something.com', 'http://example.com'];

    const corsOptionsDelegate = (req, callback) => {
    let corsOptions;

    let isDomainAllowed = whitelist.indexOf(req.header('Origin')) !== -1;
    let isExtensionAllowed = req.path.endsWith('.jpg');

    if (isDomainAllowed && isExtensionAllowed) {
        // 為此請求啟用 CORS
        corsOptions = { origin: true }
    } else {
        // 為此請求禁用 CORS
        corsOptions = { origin: false }
    }
    callback(null, corsOptions)
}

app.use(cors(corsOptionsDelegate));

回撥函數接受兩個引數,第一個是傳遞 null 的錯誤,第二個是傳遞 { origin: false } 的選項。第二個引數可以是用 Express 的 request 物件構造的更多選項。

所以 http://something.comhttp://example.com 上的 Web 應用將能夠按照自定義設定從伺服器參照擴充套件名為 .jpg 的圖片。

這樣可以成功參照資原始檔:

<img src="http://yourdomain.com/img/cat.jpg">

但是下面的檔案將會被阻止:

<img src="http://yourdomain.com/img/cat.png">

從資料來源載入允許的來源列表作

還可以用儲存在資料庫中的白名單列表或任何一種資料來源來允許 CORS:

var corsOptions = {
    origin: function (origin, callback) {
        // 從資料庫載入允許的來源列表
        // 例如:origins = ['http://example.com', 'http//something.com']
        database.loadOrigins((error, origins) => {
            callback(error, origins);
        });
    }
}

app.use(cors(corsOptions));

原文:https://stackabuse.com/handling-cors-with-node-js/

作者:Janith Kasun

更多程式設計相關知識,可存取:!!

以上就是詳解使用Node.js怎麼處理CORS的詳細內容,更多請關注TW511.COM其它相關文章!