Nuxt.js 使用 axios、proxy 解決跨域請求 (CORS)


為什麼需要特別處理跨域請求?

瀏覽器為了防止惡意網站竊取資料,採用同源政策,防止惡意網站 B 竊取你在 A 站的 Cookie,
像是藉由你已登入 Amazon 的 Cookie,盜用身份買東西。
「同源」定義很簡單,以下三個參數都相同


    [protocol]://[domain]:[port]

nuxt 提供了 axios module 以及 proxy module,使用這兩個 module 搭配某些設定,讓我們可以透過 proxy 這個代理伺服器向後端伺服器發請求,
由於請求是由代理 server 向後端 server 發起,而並非由瀏覽器,所以就不會有 CORS 問題了。

proxy module 的原理其實就是把 nuxt 的 web server 當成 proxy server,也就是在瀏覽器端向提供網頁的伺服器發出請求,
讓網頁伺服器去和我們真正要打的後端伺服器要資料(簡單說就是把自己當做 proxy)。
示意圖如下:

Nuxt Proxy

Step.1 安裝 axios module 以及 proxy module


    npm install @nuxtjs/axios @nuxtjs/proxy

Step.2 在 nuxt.config.js 檔案中進行設定


  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy'
  ],
  axios: {
    proxy: true,
    prefix: '/api',
    credentials: true,
  },
  proxy: {
    '/api': {
      target: 'https://example.com/', 
      changeOrigin: true, 
      pathRewrite: {
        '^/api': '',
      },
    }
  },

proxy 配置意涵(本地 url 以 http://localhost:3000/ 為例)

proxy 中的'/api:表示 Client Request 以 /api 開頭會對應到的網址,例如:http://localhost:3000/api
prefix:用來配置打向 API 的 baseUrl。以上面的程式碼為例,我們在這裡的 baseUrl 會是 https://example.com/api
target:表示要代理請求的 API url ( server 地址)當請求 /api/users 時,從請求 http://localhost:3000/api/users 代理到 https://example.com/api/users
pathRewrite:定義 url 中 path 的重寫規則。當請求/api/users時,其實是想對 https://example.com/users 發出請求,這時就必須把前綴 path api 刪除

Step3. 新增 axios plugin

在 plugin 資料夾新增一隻 axios.js 檔案:


    export default function ({ $axios, redirect }) {
        //Authorization
      $axios.setHeader('Content-Type', 'application/json')
    }

然後在 nuxt.config.js 當中的 plugin 設定把這隻 plugin 引入:


    plugins: [
      '~/plugins/axios'
    ],

假設我只有一隻 request 需要 proxy 的情況該怎麼辦呢?若是這種情況,
我們就不需要在 nuxt config 當中把 axios 的設定為 proxy: true ,
而只要在 proxy 當中設定需要使用 proxy 的 url:


    proxy: {
        '/users': {
            target: 'https://example.com'
            // 向 /users 發請求時,proxy 會再向 https://example.com/users 發請求
        }
    },

並且在單獨需要用到 proxy 的地方,重新實例化一個 axios(不需要使用 nuxt 的 $axios moudule, 因為若 moudule 有設定 baseUrl 的話,會發生衝突):


    const axios = require('axios')
    const { data } = await axios.post(`/seo_check`, {
      url: check_url
    })
    // 若網址不包含 host ,預設會向本地的網頁伺服器發出請求
An unhandled error has occurred. Reload 🗙