引言:为什么你的项目需要 API 网关?
\n\n想象一下:你正在用 TypeScript 编写一个初创公司或企业级应用程序。你已经有了用户服务、订单服务和通知服务。每个服务都运行在自己的端口(甚至自己的服务器)上,通过 HTTP 通信,并使用自己的数据库。一切正常,但客户端(前端、移动应用程序)开始不堪重负:为了加载一个个人资料页面,它需要向不同的服务发出 4-5 个请求,处理不同的错误格式,并且还需要在每个服务中进行身份验证。
\n\n这时,API 网关 登场了——它是所有客户端的统一入口点。它负责路由、身份验证、数据聚合、缓存,甚至响应转换。在本文中,我们将从头开始用 TypeScript 编写一个真正的 API 网关,讨论模式和反模式,并展示如何避免踩坑。
\n\n通俗解释什么是 API 网关
\n\nAPI 网关是客户端和内部服务之间的一个中间层。客户端(浏览器、移动应用、外部 API)只与网关通信。网关查看请求路径,验证令牌,然后将请求转发到相应的微服务。有时,它甚至会将来自多个服务的响应合并为一个——这称为聚合。
\n\n为什么在 TypeScript 生态系统中需要它?因为 TypeScript 为我们提供了类型、接口和严谨性,而网关是验证数据并将其转换为统一契约的理想场所。
\n\n架构:它在 TypeScript 中如何工作
\n\n让我们设计一个简单但可用的架构。我们将拥有:
\n\n- \n
- 网关(我们的 TypeScript 服务) — 端口 3000,唯一的入口点。 \n
- 用户服务 — 端口 4001,REST API。 \n
- 订单服务 — 端口 4002,REST API。 \n
- 通知服务 — 端口 4003,REST API。 \n
所有内部服务都运行在自己的网络(例如 Docker 网络)中,并且对外部不可见。客户端仅与网关通信。
\n\n// 项目结构\ngateway/\n├── src/\n│ ├── routes/\n│ │ ├── userRoutes.ts\n│ │ ├── orderRoutes.ts\n│ │ └── notificationRoutes.ts\n│ ├── middleware/\n│ │ ├── authMiddleware.ts\n│ │ ├── rateLimiter.ts\n│ │ └── cacheMiddleware.ts\n│ ├── services/\n│ │ └── proxyService.ts\n│ ├── types/\n│ │ └── index.ts\n│ └── index.ts\n├── package.json\n└── tsconfig.json\n\n\n用 TypeScript 编写基本 API 网关
\n\n我们从安装依赖开始。我们需要 Express(最流行的框架)、用于代理的 http-proxy-middleware 以及一些实用工具。
\n\nnpm init -y\nnpm install express http-proxy-middleware cors helmet express-rate-limit\nnpm install -D typescript @types/node @types/express ts-node nodemon\n\n\n创建 tsconfig.json:
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "outDir": "./dist",\n "rootDir": "./src",\n "strict": true,\n "esModuleInterop": true,\n "skipLibCheck": true,\n "forceConsistentCasingInFileNames": true\n },\n "include": ["src/**/*"],\n "exclude": ["node_modules"]\n}\n\n\n现在编写主文件 src/index.ts:
import express, { Request, Response } from 'express';\nimport cors from 'cors';\nimport helmet from 'helmet';\nimport { createProxyMiddleware } from 'http-proxy-middleware';\nimport { authMiddleware } from './middleware/authMiddleware';\nimport { rateLimiter } from './middleware/rateLimiter';\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\n\n// 全局中间件\napp.use(helmet());\napp.use(cors());\napp.use(express.json());\napp.use(rateLimiter);\n\n// 用户服务的代理\napp.use('/api/users', auth