JavaScript >> Javascript 文檔 >  >> Node.js

使用 Node.js 處理 CORS

簡介

在本文中,我們將了解 CORS 是什麼,如何使用 Express 配置 CORS,以及如何根據需要自定義 CORS 中間件。

什麼是 CORS

CORS跨域資源共享的簡寫 .它是一種允許或限制 Web 服務器上請求的資源的機制,具體取決於發起 HTTP 請求的位置。

此策略用於保護某個 Web 服務器不被其他網站或域訪問。例如,只有允許的域才能訪問服務器中的託管文件,例如樣式表、圖像或腳本。

如果您目前在 http://example.com/page1 你指的是來自 http://image.com/myimage.jpg 的圖像 除非 http://image.com 否則您將無法獲取該圖像 允許與 http://example.com 進行跨域共享 .

有一個名為 origin 的 HTTP 標頭 在每個 HTTP 請求中。它定義了域請求的來源。我們可以使用標頭信息來限製或允許來自我們網絡服務器的資源來保護它們。

例如,當您仍處於開發階段時 - 如果您正在使用 React 等前端庫,您的前端應用程序將在 http://localhost:3000 上提供服務 .同時,您的 Express 服務器可能在不同的端口上運行,例如 http://localhost:2020 .

因此,您需要在這些服務器之間允許 CORS。

如果您在瀏覽器控制台中看到此常見錯誤。 CORS 限制可能是問題所在:

當您提供公共 API 並希望控制對某些資源的訪問以及人們如何使用它們時,CORS 非常有用。

此外,如果您想在不同的網頁上使用自己的 API 或文件,您可以簡單地配置 CORS 以允許這樣做,同時仍然阻止其他人。

使用 Express 配置 CORS

讓我們從一個新項目開始。我們將為它創建一個目錄,輸入它並運行 npm init 使用默認設置:

$ mkdir myapp
$ cd myapp
$ npm init -y

然後讓我們安裝所需的模塊。我們將使用 expresscors 中間件:

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

然後讓我們開始創建一個包含兩個路由的 express 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.comhttp://www.example.com 引用內容 .

因此,http://www.differentdomain.com 上的網頁 可以使用我們的域作為圖像的來源:

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

為單個路由啟用 CORS

但是如果你需要某個路由可以訪問而不是其他路由,你可以配置 cors 在某個路由中作為中間件而不是配置到整個應用中:

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

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

這將允許任何域訪問某個路由。所以在你的情況下,只有 / 每個域都可以訪問路由。 /:name 只有在與 API 相同的域中發起的請求才能訪問路由,即 http://localhost:2020 在我們的例子中。

例如,如果您嘗試向 / 來自不同來源的路徑 - 它會成功,您將獲得 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));

如果您嘗試在不同的網絡應用程序中運行此代碼,您應該會看到以下錯誤:

使用選項配置 CORS

您還可以使用 CORS 的配置選項來進一步自定義。您可以使用配置來允許單個域或子域訪問,配置允許的 HTTP 方法例如 GETPOST 根據您的要求。

以下是使用 CORS 選項允許單個域訪問的方法:

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

app.use(cors(corsOptions));

如果您在源中配置域名 - 服務器將允許來自配置的域的 CORS。所以 API 可以從 http://localhost:8080 訪問 在我們的例子中,並被其他域屏蔽。

如果我們發送 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));

// Or

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 // For legacy browser support
    methods: "GET, PUT"
}

app.use(cors(corsOptions));

如果我們發送 POST 來自 http://localhost:8080 的請求 , 它會被瀏覽器屏蔽為只有 GETPUT 支持:

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。

例如,假設您要允許 .jpg 的 CORS 共享 文件 http://something.comhttp://example.com

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) {
        // Enable CORS for this request
        corsOptions = { origin: true }
    } else {
        // Disable CORS for this request
        corsOptions = { origin: false }
    }
    callback(null, corsOptions)
}

app.use(cors(corsOptionsDelegate));

回調函數將接受兩個參數。第一個是我們通過 null 的錯誤 第二個是我們通過 { origin: false } 的選項 .第二個參數可以是許多使用 request 構造的選項 來自 Express 請求處理程序的對象。

所以一個託管在 http://something.com 上的網絡應用程序 或 http://example.com 將能夠使用 .jpg 引用圖像 正如我們在自定義函數中配置的那樣,從服務器擴展。

因此,以下圖像附件將從其中任何一個中成功:

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

但是下面的附件會被屏蔽:

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

從數據源加載允許的來源列表

您還可以使用數據庫中允許的域列表或使用任何支持數據源來允許 CORS:

var corsOptions = {
    origin: function (origin, callback) {
        // Loading a list of allowed origins from the database
        // Ex.. origins = ['http://example.com', 'http//something.com']
        database.loadOrigins((error, origins) => {
            callback(error, origins);
        });
    }
}

app.use(cors(corsOptions));

結論

在本文中,我們介紹了 CORS 是什麼以及如何使用 Express 配置它。然後,我們為所有請求、特定請求設置了 CORS,添加了選項和限制,並為動態 CORS 配置定義了自定義函數。


Tutorial JavaScript 教程
  1. 介紹 Proximity API

  2. 我是編碼新手,正在嘗試在家學習 Web 開發,:)

  3. 我如何使用 Font Awesome [更新] 重新製作 DEV 徽章

  4. 在 React 中構建 Slack huddle 克隆

  5. ReactJS 受保護的路由

  6. 辯論:React Js 對 SEO 不利嗎?

  7. 我差點在麵包店建圖書館的那一天

  1. 如何在 TypeScript 中檢查數組是否為空

  2. 如何檢查變量是否不是假的,但 0 在 Javascript 中通過

  3. 星球大戰使 CSS3 動畫和轉換變得有意義

  4. Deno 中的 Oak 入門

  5. ChartJS 電子郵件 HTTP 請求 API

  6. 如何解決 Next.js ChunkLoadError:Loading chunk node_modules_next_dist_client_dev_noop_js failed 錯誤

  7. 你真的了解 JavaScript 嗎?第 1 部分:未定義

  1. 什麼是 Javascript 中的函數表達式

  2. 作為開發人員的 7 個令人不安的事實。

  3. 使用 MySQL 作為 BigQuery 的緩存層

  4. 如何使用 Webpacks 模塊聯合插件構建微前端