使用NodeJS建立一个API代理服务器来隐藏公共API密钥的教程

277 阅读4分钟

用API代理服务器隐藏你的API密钥

这篇文章/教程的主要目的是演示如何通过使用NodeJS建立一个API代理服务器来隐藏公共API密钥。

在这篇文章/教程中,我们将使用NodeJS创建一个API代理服务器,这背后的主要原因是告诉你如何隐藏公共API密钥,而不是像我过去那样将它们暴露在公众面前。我们所有人都曾经创建过一个应用程序,只是为了了解一个新的库或框架,而实现这一目的的最好方法是使用一个开放的API(如TMDB)。

这些开放的API大多需要在请求的URL中或在发出请求前的头文件中加入API密钥。无论哪种方式,API密钥都可能被窃取,并被实际上不拥有此密钥的人使用。结果,你可能会被暂停帐户,或者你的应用程序不能像你所期望的那样工作。

请记住这一点。API密钥属于你的应用程序的服务器方。

不用多说,让我们来创建这个API代理服务器。为了这篇文章/教程的目的,我们将使用Weather API

要求

在开始编码之前,我们需要有以下的条件:

  • API密钥
    打开OpenWeatherMapAPI网站,建立一个免费账户,进入我的API密钥并创建一个。
  • 具备JavaScript和NodeJS的基本知识
  • 咖啡

依赖关系和脚本

创建应用程序的项目文件夹

外壳

cd ~/Documents/tutorials
mkdir api-proxy-server && cd api-proxy-server
npm init -y

安装所需的NPM包

外壳

npm install -S express cors dotenv axios
npm install -D nodemon # for faster development

在package.json文件中准备好脚本

JSON

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon --config nodemon.json"
  }
}

让我们看一下项目的文件夹和文件,以便对结构有一个更清晰的印象:

server/
├── src
│   ├── utils
│   │   └── env.js
│   └── routes
│       └── index.js
├── package.json
├── nodemon.json
├── index.js
└── .env
3 directories, 6 files

在项目的根部创建一个index.js 和一个nodemon.json 文件。

JSON

// nodemon.json
{
  "verbose": true,
  "ignore": ["node_modules/"],
  "watch": ["./**/*"]
}

在我们开始编辑条目 (index.js) 文件之前,我们需要创建另外两个有用的文件。第一个是.env 文件,我们所有的环境变量都在其中。这将是一个可重复使用的文件,以便能够与其他公共API(除了OpenWeatherMap API)一起使用它。

API_PORT = 1337
API_BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
API_KEY = "1d084c18063128c282ee3b41e91b6740" # not actually api key; use a valid one

另一个文件是src/utils/env.js ,它负责读取和导出所有的环境变量。

JavaScript

require("dotenv").config();

module.exports = {
  port: Number(process.env.API_PORT) || 3000,
  baseURL: String(process.env.API_BASE_URL) || "",
  apiKey: String(process.env.API_KEY) || "",
};

现在是编辑主文件的时候了,为这个代理服务器应用程序添加一些逻辑。

脚本

// imports
const express = require("express");
const cors = require("cors");
const env = require("./src/utils/env");

// Application
const app = express();

// Middlewares
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

// Routes
app.use("/api", require("./src/routes")); // Every request that starts with /api will be handled by this handler

// This route will handle all the requests that are not handled by any other route handler
app.all("*", (request, response, next) => {
  return response.status(404).json({ message: "Endpoint not found!" });
});

// Bootstrap server
app.listen(env.port, () => {
  console.log(`Server is up and running at http://localhost:${env.port}`);
});

这里的事情非常简单,它是一个基本的ExpressJs服务器应用程序。在顶部,我们已经有了所需的导入。然后,我们有一些需要的中间件,如JSON 中间件,它负责解析带有JSON有效载荷的传入请求,并基于body-parser 。接下来,我们有路由,在这里我们管理端点和它们的处理程序。最后,我们得到了服务器的引导。

让我们看一下/api 路由的处理程序。

JavaScript

// server/src/routes/index.js
const router = require("express").Router();
const { default: axios } = require("axios");
const env = require("../utils/env");

// [GET] Current weather data
router.get("/", async (request, response, next) => {
  try {
    const query = request.query || {}; 
    const params = {
      appid: env.apiKey, // required field
      ...query,
    };
    const { data } = await axios.get(env.baseURL, { params });

    return response.status(200).json({
      message: "Current weather data fetched!",
      details: { ...data },
    });
  } catch (error) {
    const {
      response: { data },
    } = error;
    const statusCode = Number(data.cod) || 400;
    return response
      .status(statusCode)
      .json({ message: "Bad Request", details: { ...data } });
  }
});

module.exports = router;

GET 请求处理函数是将我们在调用它时提供的查询字段作为输入。

例如,如果我们没有这个API代理服务器,我们的请求会是这样的:https://api.openweathermap.org/data/2.5/weather?q=Thessaloniki,Greece&appid={API key} ,但现在我们已经有了它,我们的请求看起来是这样的:http://localhost/api?q=Thessaloniki,Greece 。没有必要添加必要的字段appid ,因为代理服务器自己把它作为一个请求参数添加。当我们在OpenWeatherMap API上进行请求时,我们没有显示API密钥。

总结

主要的概念是将你的公共API密钥隐藏在API代理服务器后面,以防止用户窃取你的密钥。为了达到这个目的,我们可以创建一些端点,将实际开放的API的端点包裹起来,在每个需要这个密钥的请求中,将API密钥放在代理服务器里面作为环境变量。这种方法的明显缺点是,这是一个耗时的过程,在某些情况下,甚至不需要。

你可以在这里得到这个API代理服务器的源代码。