NEXT 跨域问题的两种解决方案

请注意,本文编写于 460 天前,最后修改于 460 天前,其中某些信息可能已经过时。

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

添加新评论

已有 8 条评论

这个先学习下,准备要改造网站了

网站默默运行了一年 OωO

于长野 于长野 回复 @老陳网志
0 0

哈哈哈哈,是该更新了,年更一个

感谢分享啊

这位博主,您好。在浏览完您的博客文章后,感觉您的博客内容质量非常的好.
现诚挚地向您发出邀请,邀请您加入腾讯自媒体分享计划:https://cloud.tencent.com/developer/support-plan?invite_code=347bs58ysckks 。待审核成功入驻后,会在社区后台为您发放相关得腾讯云无门槛代金券以及一些实物奖励。
具体审核细则,请进入页面查看。

感谢欣赏,不过博客目前更新缓慢,自驱力不足,暂时就不加入了