使用无服务器函数保护 API 密钥

2025-06-10

使用无服务器函数保护 API 密钥

想象一下,您需要开发一个 APP 的前端,该 APP 需要从MovieDB API 获取最受欢迎的电影列表。

我们开始做吧 !

前往MovieDB并注册以获取您自己的 API 密钥并继续操作。

我们将使用 create-react-app 创建一个名为protectingapisecrets的新项目,并开始编写前端代码

npx create-react-app protectingapisecrets
cd protectingapisecrets
touch .env
npm install axios

使用您最喜欢的代码编辑器打开此项目,编辑您的.env文件并添加一个带有 API 密钥的变量

// .env

REACT_APP_API_KEY=<<your api key>>

接下来打开你的.gitignore文件并添加一行你的.env文件,最后删除src文件夹中的所有文件并创建一个干净的 i* ndex.js * App.jsApp.css

开始编码

// index.js

import React from 'react';
import ReactDOM from 'react-dom';

import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
// App.js

import React, { useState, useEffect } from "react"
import axios from "axios"
import "./App.css"

const App = () => {
  const [movies, setMovies] = useState(null)
    
    async function fetchMovies() {
        const url = `https://api.themoviedb.org/3/movie/popular?api_key=${process.env.REACT_APP_API_KEY}&language=en-US&page=1`
      const response = await axios.get(url)
        const data = response.data.results
        setMovies(data)
      }  

    useEffect(() => {
    fetchMovies()
  }, [])

    return (
    <>
      {movies === null ? (
        <div className="loading">
          <h2>Loading ...</h2>
        </div>
      ) : (
        <>
          <div className="container">
            {movies.map((movie) => (
              <div className="movie" key={movie.id}>
                <img src={`https://image.tmdb.org/t/p/w185/${movie.poster_path}`} alt={movie.title} />
              </div>
            ))}
          </div>
        </>
      )}
    </>
   )
  }

export default App
// App.css

*,
*::after,
*::before {
  margin: 0rem;
  padding: 0rem;
  box-sizing: inherit;
}

html {
  font-size: 62.5%;
  scroll-behavior: smooth;
}

body {
  box-sizing: border-box;
  background-color: #222831;
}

.loading {
  padding-top: 5rem;
  text-align: center;
}

.loading h2 {
  color: white;
  font-size: 2rem;
}

.container {
  margin: auto;
  padding: 2rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
  max-width: 110rem;
  grid-gap: 2rem;
}

.movie img {
  width: 100%;
}

太棒了,现在我们开始吧

npm start 

并检查一切是否符合我们的预期

图片 1

部署

惊人的!

我们已经完成了前端,现在是时候部署它了。

使用 Netlify,我们只需三个步骤即可轻松完成此操作:

第一步:创建一个新的 GitHub 存储库并推送您的代码。

第二步:在 Netlify 上创建帐户并将您的帐户连接到您的 GitHub。

第三:在你的 Netlify 面板上选择“从 git 创建新站点”并选择你创建的存储库,你还需要选中“显示高级”并添加一个新变量,如下所示:

图片 2

单击“部署站点”,就这样,我们现在有了应用程序的实时版本!

问题

我们将 API 密钥存储在环境变量中,以防止它在我们的代码中可用,但如果有人在浏览您的网站时打开 chrome dev tools,就可以很快找到您的密钥。

图 3

那么,我们可以做些什么来保护我们的 API 密钥?

无服务器函数

我们可以创建一个无服务器函数来为我们处理 API 调用,这样我们就不必公开我们的密钥。

让我们尝试一下,回到你的终端并运行:

npm install netlify-lambda http-proxy-middleware env-cmd
mkdir functions
touch netlify.toml

更新package.json文件中的脚本,使其如下所示:

// package.json

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
        "lambda-serve": "env-cmd netlify-lambda serve functions",
        "lambda-build": "netlify-lambda build functions"
  },

将以下行添加到netlify.toml文件并将函数文件夹添加到.gitignorefile

// netlify.toml

[build]
    functions = "lambda"

将名为setupProxy.js的文件添加到您的src文件夹并粘贴以下代码:

// setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/.netlify/functions/',
    createProxyMiddleware({
      target: 'http://localhost:9000',
      "pathRewrite": {
        "^/\\.netlify/functions": ""
      }
    })
  );
};

此代理设置将允许您根据您所在的环境 ping 不同的端点,如果您处于开发状态,则需要 ping本地主机,而在生产状态,您需要./netlify/functions端点。

编写函数代码

让我们在函数目录中创建一个名为getMovies.js的文件

// getMovies.js

const axios = require("axios")

exports.handler = function(event, context, callback) {
    const { API_KEY } = process.env

    const url = `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}&language=en-US&page=1`

    const send = body => {
        callback(null, {
            statusCode: 200,
            body: JSON.stringify(body)
        })
    }

    const getMovies = async () => {
        const response = await axios.get(url)
        const data = response.data.results

        send(data)
    }

    getMovies()
}

现在我们需要编辑App.js中的fetchMovies函数以使用 serveless 函数,而不是直接 ping moviedb api:

async function fetchMovies() {
    const url = `/.netlify/functions/getMovies`

    const response = await axios.get(url)
    const data = response.data
    setMovies(data)
  }

最后编辑.env文件并将变量名称从REACT_APP_API_KEY更改为API_KEY

太好了,让我们测试一下吧!

打开两个终端窗口,在第一个窗口上运行npm start ,在第二个窗口上运行 npm run lambda-serve,然后检查网络选项卡

图片 4

太棒了,我们正在调用隐藏 api 真实端点的无服务器函数,让我们将其部署到 Netlify,打开你的终端并运行:

git add .
git commit -m "finished version"
git push

当你将提交推送到你的 GitHub 仓库时,Netlify 会触发你网站的新部署。你只需额外完成一步即可完成:打开 Netlify 面板,将你在第一次部署时创建的环境变量名称从REACT_APP_API_KEY更改为API_KEY。

图 5

我们已经完成了,很快再见!

您可以在这里查看我的 GitHub 仓库:https://github.com/NunoCPNP/protectapisecrets

我部署的版本在这里:https://protectingapisecrets.netlify.app/

鏂囩珷鏉ユ簮锛�https://dev.to/nunocpnp/protecting-api-keys-with-serverless-functions-2ck7
PREV
您的第一个使用 React 和 React-Spring 的响应式动画导航栏
NEXT
为什么需要终端