0

0

掌握Next.js生产环境中的环境变量:避免秘密值不可见的陷阱

聖光之護

聖光之護

发布时间:2025-09-20 23:02:20

|

508人浏览过

|

来源于php中文网

原创

掌握Next.js生产环境中的环境变量:避免秘密值不可见的陷阱

本文深入探讨了Next.js应用在生产环境中处理环境变量时遇到的常见问题,特别是与NEXT_PUBLIC_前缀相关的误解。我们将详细解释服务器端和客户端环境变量的区别,指出错误使用前缀导致秘密值无法加载的原因,并提供两种核心解决方案:一是确保服务器端秘密值不使用NEXT_PUBLIC_前缀;二是通过API路由安全地向客户端暴露公共环境变量,从而解决生产环境配置难题。

理解Next.js中的环境变量

在next.js项目中,环境变量的管理是构建可配置应用的关键。next.js对环境变量的处理方式进行了区分,以确保安全性和灵活性:

  1. 客户端环境变量 (Client-side Environment Variables): 这些变量必须以NEXT_PUBLIC_作为前缀。它们会在构建时被嵌入到客户端JavaScript包中,因此可以在浏览器环境中直接访问(例如,通过process.env.NEXT_PUBLIC_API_KEY)。由于这些变量最终会暴露给用户,所以绝不能存放任何敏感信息。
  2. 服务器端环境变量 (Server-side Environment Variables): 这些变量不应带有NEXT_PUBLIC_前缀。它们只在Node.js环境中(例如,API路由、getServerSideProps、getStaticProps等)可用,不会被打包到客户端JavaScript中。这使得它们成为存储敏感信息(如API密钥、数据库凭据等)的理想选择。

生产环境中的秘密值不可见问题分析

许多开发者在本地开发时,会将所有环境变量都定义在.env.local文件中,并且由于本地开发服务器的行为,即使是带有NEXT_PUBLIC_前缀的变量,在服务器端API路由中也可能意外地被访问到。然而,一旦部署到生产环境,这种行为就会发生变化。

原始问题中,Google Sheets API的凭据(NEXT_PUBLIC_GOOGLE_CLIENT_EMAIL和NEXT_PUBLIC_GOOGLE_PRIVATE_KEY)被错误地使用了NEXT_PUBLIC_前缀。这些凭据是用于服务器端与Google API进行认证的敏感信息,本应只在服务器端API路由中访问。当它们被定义为NEXT_PUBLIC_时,Next.js在构建时会尝试将它们暴露给客户端,但由于它们是敏感的,或者在生产构建流程中处理方式不同,最终导致在服务器端API路由中无法正确读取,从而引发“The incoming JSON object does not contain a client_email field”之类的错误。

即使环境变量通过AWS等云服务注入,如果命名约定不符合Next.js的规范,或者在服务器端代码中试图以客户端变量的方式访问服务器端秘密,问题依然会出现。

解决方案一:正确使用环境变量前缀

对于只应在服务器端使用的敏感信息,绝不能使用NEXT_PUBLIC_前缀。

示例:

假设你的Google API凭据需要用于Next.js的API路由(pages/api/submit.js),它们应该这样定义在你的.env或生产环境配置中:

# .env 或生产环境配置
GOOGLE_CLIENT_EMAIL=your-client-email@example.com
GOOGLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n
GOOGLE_SHEET_ID=your-sheet-id

然后在你的API路由中,你可以直接通过process.env访问它们:

// pages/api/submit.js
import { google } from 'googleapis';

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).send('Only POST requests are allowed!');
  }

  try {
    const auth = new google.auth.GoogleAuth({
      credentials: {
        client_email: process.env.GOOGLE_CLIENT_EMAIL, // 注意:不再有 NEXT_PUBLIC_ 前缀
        private_key: process.env.GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n'),
      },
      scopes: [
        'https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/drive.file',
        'https://www.googleapis.com/auth/spreadsheets',
      ],
    });
    // ... 后续逻辑
    return res.status(201).json({ data: response.data });
  } catch (error) {
    console.error('API submission error:', error);
    return res.status(error.code || 500).send({ message: error.message || 'An unknown error occurred.' });
  }
}

注意事项:

  • 部署环境配置: 在生产环境中,这些非NEXT_PUBLIC_前缀的变量通常通过CI/CD管道、云服务提供商的环境变量设置(如Vercel、Netlify、AWS ECS/Lambda、Docker容器环境变量)来注入。确保这些平台正确地设置了这些变量。
  • Dockerfile: 如果使用Docker,环境变量可以通过docker run -e KEY=VALUE或在Dockerfile中使用ENV KEY=VALUE来设置。但更推荐在运行时注入,以避免将秘密信息硬编码到镜像中。
  • 重启服务: 任何环境变量的更改都需要重新启动Next.js服务器或重新部署应用才能生效。

解决方案二:安全地向客户端暴露公共环境变量

有时,即使是带有NEXT_PUBLIC_前缀的变量(例如Google Tag Manager ID),也可能在某些生产部署环境中无法正确加载。这通常发生在客户端代码尝试访问这些变量时。为了确保这些公共变量在客户端可用,并且避免直接在构建时硬编码可能带来的问题(例如,需要动态切换环境配置),可以创建一个API路由来专门暴露这些公共环境变量。

Facet
Facet

Facet.ai是一款AI图像生成和编辑工具,具备实时图像生成和编辑功能

下载

示例:

创建一个API路由,例如pages/api/env.js,用于返回所有以NEXT_PUBLIC_开头的环境变量:

// pages/api/env.js
export default function handler(req, res) {
  // 过滤出所有以 'NEXT_PUBLIC_' 开头的环境变量
  const publicEnv = Object.keys(process.env)
    .filter((key) => key.startsWith('NEXT_PUBLIC_'))
    .reduce((acc, key) => {
      acc[key] = process.env[key];
      return acc;
    }, {});

  // 返回这些公共环境变量
  res.status(200).json(publicEnv);
}

然后在客户端组件中,你可以通过fetch请求这个API路由来获取公共环境变量:

// components/MyClientComponent.js (或任何需要客户端环境变量的地方)
import React, { useEffect, useState } from 'react';

function MyClientComponent() {
  const [envConfig, setEnvConfig] = useState({});

  useEffect(() => {
    async function fetchEnv() {
      try {
        const response = await fetch('/api/env'); // 请求你创建的API路由
        const data = await response.json();
        setEnvConfig(data);
      } catch (error) {
        console.error('Failed to fetch public environment variables:', error);
      }
    }
    fetchEnv();
  }, []);

  // 现在你可以通过 envConfig 访问这些变量,例如:
  // const gtmId = envConfig.NEXT_PUBLIC_GTM_ID;

  return (
    
{envConfig.NEXT_PUBLIC_GTM_ID ? (

Google Tag Manager ID: {envConfig.NEXT_PUBLIC_GTM_ID}

) : (

Loading GTM ID...

)}
); } export default MyClientComponent;

注意事项:

  • 安全性: 这种方法仅适用于非敏感的公共环境变量。切勿通过此方法暴露任何敏感信息,因为这些信息最终会通过网络请求传输到客户端。
  • 性能: 每次客户端加载时都会发出一个额外的网络请求。对于频繁使用的公共变量,如果它们在构建时是固定的,并且不涉及敏感信息,仍然推荐直接使用NEXT_PUBLIC_前缀让Next.js在构建时嵌入。这种API路由方法更适用于那些在构建后可能需要动态调整,或者在某些特殊部署场景下NEXT_PUBLIC_前缀失效的情况。

总结

Next.js环境变量的正确使用是确保应用在生产环境中稳定运行的关键。核心原则是:

  1. 服务器端秘密值:不使用NEXT_PUBLIC_前缀,并通过部署环境(如.env文件、Docker环境变量、云服务配置)安全注入。
  2. 客户端公共值:使用NEXT_PUBLIC_前缀。如果遇到加载问题,可以考虑通过API路由动态获取,但需注意安全性和性能。

遵循这些最佳实践,可以有效避免在生产环境中因环境变量配置不当而导致的“秘密值不可见”问题。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

557

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

395

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

756

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

478

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

474

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

1051

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

659

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

554

2023.09.20

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

0

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号