You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js调用私有环境变量API时遇500与Axios错误

葡萄酒搭配应用Next.js API路由问题排查

问题背景

我正在用Next.js开发一款葡萄酒搭配应用,用户点击葡萄酒类型(如霞多丽)时,调用第三方API获取推荐的食物搭配。使用NEXT_PUBLIC环境变量时功能正常,但不想暴露私有API密钥,于是尝试在pages/api文件夹下实现服务端API路由,结果遇到500 (Internal Server Error)和Axios错误。

了解到getStaticProps()必须在页面中调用,但我的API请求是在组件内发起的,所以无法使用该方案。

环境配置

.env.local内容:

API_KEY=<my api key>
BASE_URL=https://api.spoonacular.com/

服务端API路由代码(pages/api/wineWithFood.js)

import axios from 'axios';

export default async function wineWithFood(req, res) {
  const {
    query: { wine },
  } = req;

  const url = `${process.env.BASE_URL}food/wine/dishes?wine=${wine}&apiKey=${process.env.API_KEY}`;

  const response = await axios.get(url);
  res.status(200).json({
    data: response.data,
  });
}

初始组件调用代码

const getPairing = async () => {
    axios.get(`/api/wineWithFood?wine=${wine}`, {
      headers: {
        Accept: 'application/json',
        'Access-Control-Allow-Origin': '*',
      },
    })
      .then((response) => response)
      .then((response) => {
      setData(response.data.pairings)
      })
    .catch((err) => console.log(err))
  }

const handleChange = (e) => {
    e.preventDefault();

    setWine(e.target.value);
    getPairing();
  };

console.log(wine)

初始问题

  • 请求无法捕获葡萄酒类型,虽然浏览器控制台console.log(wine)显示值正常
  • 调用API时返回400状态码,提示「葡萄酒参数不能为空」

修改后的组件代码

const getPairing = async (wine) => {
    axios
      .get(`/api/wineWithFood?wine=${wine}`, {
        headers: {
          Accept: 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      })
      .then((response) => response)
      .then((response) => {
        setData(response.data.pairings);
        console.log(response.data.pairings);
      })
      .catch((err) => console.log(err));
  };

const handleChange = (e) => {
    e.preventDefault();
    setWine(e.target.value);

    getPairing(wine);
  };

修改后仍存在的问题

首次点击葡萄酒类型仍报错,第二次点击同一选项时,浏览器控制台显示wine值正常,终端能看到第三方API返回的正确数据,但前端依旧报500错误。


排查与修复方案

1. 解决状态更新异步导致的参数延迟问题

setWine是异步操作,修改后的handleChange中调用getPairing(wine)时,wine还是更新前的旧值。直接传递e.target.value给getPairing即可:

const handleChange = (e) => {
  e.preventDefault();
  const selectedWine = e.target.value;
  setWine(selectedWine);
  getPairing(selectedWine);
};

2. 完善API路由的错误处理与参数校验

当前API路由未做错误捕获,第三方API请求失败会直接抛出未处理错误导致500。添加参数校验、错误捕获和特殊字符处理:

import axios from 'axios';

export default async function wineWithFood(req, res) {
  try {
    const { query: { wine } } = req;
    // 提前校验参数,避免无效请求
    if (!wine) {
      return res.status(400).json({ error: '葡萄酒参数不能为空' });
    }
    // 对葡萄酒名称编码,处理空格、特殊字符
    const encodedWine = encodeURIComponent(wine);
    const url = `${process.env.BASE_URL}food/wine/dishes?wine=${encodedWine}&apiKey=${process.env.API_KEY}`;
    
    const response = await axios.get(url);
    // 直接返回第三方API的数据,减少嵌套
    res.status(200).json(response.data);
  } catch (err) {
    // 打印错误日志便于排查
    console.error('第三方API请求失败:', err);
    // 返回对应错误状态码和信息
    res.status(err.response?.status || 500).json({ 
      error: err.response?.data?.error || err.message 
    });
  }
}

3. 优化前端错误日志与请求头部

  • 前端请求中的Access-Control-Allow-Origin是响应头,不需要在请求中设置,直接删除该头部
  • 完善错误捕获,打印完整错误信息:
const getPairing = async (wine) => {
  axios.get(`/api/wineWithFood?wine=${wine}`)
    .then((response) => {
      setData(response.data.pairings);
      console.log(response.data.pairings);
    })
    .catch((err) => {
      // 打印详细错误信息,包括后端返回的错误内容
      console.log('请求错误:', err.response?.data || err.message);
    });
};

4. 验证环境变量加载

在API路由中临时添加日志(生产环境上线前删除),确认环境变量是否正确加载:

console.log('BASE_URL:', process.env.BASE_URL);
console.log('API_KEY已配置:', !!process.env.API_KEY);

内容的提问来源于stack exchange,提问作者techmeowt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:55:25