用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代理服务器的源代码。