banner
rabithua

rabithua

twitter
github

NEXT 跨域問題的兩種解決方案

Next 是一個 react 框架,能夠前後端一體化,用來做項目是一個不錯的選擇。本文記錄一下幾天前開發過程處理跨域問題的過程。【推薦方案二,方案二也更簡單,不過需要一點點 nodejs 基礎】

開始前請確認自己準備的跨域接口可以正常調用,如果實踐過程中出現錯誤也請先檢查接口是否正常,然後再檢查本地配置的跨域是否有錯。避免忙碌半天發現原本的接口就存在問題 :@(裝大款)

方案一:項目目錄下新建 server.js 文件,搭配 package.json scripts 啟動選項,實現開發環境跨域#

實現 >>>#

  • 創建 server.js 文件,目錄為項目根目錄,也就是 package.json 同級目錄,文件代碼如下
// server.js
const express = require('express')
const next = require('next')
const { createProxyMiddleware } = require('http-proxy-middleware')

//此處為跨域具體配置
const devProxy = {
    '/email': {
        target: 'https://api.postmarkapp.com/', 
        changeOrigin: true
    }
}

//以下內容保持不變,如果你不懂,請不要修改
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({
    dev
})
const handle = app.getRequestHandler()

app.prepare()
    .then(() => {
        const server = express()
        if (dev && devProxy) {
            Object.keys(devProxy).forEach(function (context) {
                // http-proxy-middleware 新用法2
                server.use(createProxyMiddleware(context, devProxy[context]))
            })
        }

        server.all('*', (req, res) => {
            handle(req, res)
        })

        server.listen(port, err => {
            if (err) {
                throw err
            }
            console.log(`> Ready on http://localhost:${port}`)
        })
    })
    .catch(err => {
        console.log('An error occurred, unable to start the server')
        console.log(err)
    })

  • 示例內容中調用的是一個 postmark 發送郵件的接口,原接口地址 https://api.postmarkapp.com/emailget 請求。
  • 按照以上寫法,實際請求方法如下
import axios from "axios";

export const waitlistEmailSend = (data: any) => {
  return new Promise((resolve, reject) => {
    try {
      axios({
        method: "post",
        url: "/email",
        data,
        headers: {
          Accept: "application/json",
          "X-Postmark-Server-Token": "***TOKEN***",
          "Content-Type": "application/json",
        },
      }).then((res: any) => {
        // console.log(res.code);
        if (res.status == 200) {
          resolve(res);
        } else {
          reject(res);
        }
      });
    } catch (error) {
      console.error(error);
      reject(error);
    }
  });
};
  • package.json 配置跨域啟動 "dev:node-middleware": "node server.js",然後通過 npm run dev:node-middleware 啟動項目,調用上面封裝的請求。
{
...
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "dev:node-middleware": "node server.js"
  }
...
}
  • 可見,請求本地 /email 接口實際請求被中間件轉發到了 https://api.postmarkapp.com/email ,跨域成功,其中 f12 頁面網絡請求顯示為對 localhost 請求。

方案二:跨域接口封裝在 Next 自帶的後端 api ,前端請求封裝後的 api 實現項目跨域#

一般 Next 新建的項目下都會有 pages/api/hello.ts 這個文件,api 文件夾下也就是 Next 自帶的 nodejs 後端,在此處請求跨域接口不會觸發跨域報錯,其實也很好理解,後端就相當於本地,你的所有請求都是直接發起的,並沒用像前端那樣有自己的域名,所以也就不存在跨域問題。
如果你懂 nodejs 的話可以跳過教程了,一切都和你 nodejs 後端的用法一樣

實現 >>>#

  • pages/api/waitlistemail.ts 創建 Next 的後端 api ,示例代碼如下
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from "axios";
import type { NextApiRequest, NextApiResponse } from "next";

type Data = {
  code: number;
  data: any;
  errMsg: string;
};

export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  console.log(req.body);
  if (req.body.To) {
    console.log("send");
    try {
      axios({
        method: "post",
        url: "https://api.postmarkapp.com/email",
        data: req.body,
        headers: {
          Accept: "application/json",
          "X-Postmark-Server-Token": "***TOKEN***",
          "Content-Type": "application/json",
        },
      }).then((r: any) => {
        console.log(r.status);
        if (r.status == 200) {
          res
            .status(200)
            .json({ code: 0, data: "", errMsg: "Email send success!" });
        } else {
          res
            .status(200)
            .json({ code: 1, data: "", errMsg: "Email send fail!" });
        }
      });
    } catch (error) {
      res
        .status(200)
        .json({ code: 1, data: "", errMsg: "Email send success!" });
    }
  } else {
    res.status(200).json({ code: 1, data: "", errMsg: "Email send fail!" });
  }
}

  • Next 前端調用接口,代碼如下
import axios from "axios";

export const waitlistEmailSend = (data: any) => {
  return new Promise((resolve, reject) => {
    try {
      axios({
        method: "post",
        url: "/api/waitlistemail",
        data,
      }).then((res: any) => {
        // console.log(res);
        if (res.data.code == 0) {
          resolve(res);
        } else {
          reject(res);
        }
      });
    } catch (error) {
      reject(error);
    }
  });
};

  • 調用接口,請求成功,依然是對 localhost 的請求。

相關鏈接: Nextjs axios

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。