Skip to content

Commit e02ab1f

Browse files
feat: 新增限流功能 (#718)
* 请求速率限制 * perf: 优化代码 --------- Co-authored-by: ChenZhaoYu <790348264@qq.com>
1 parent 47dc009 commit e02ab1f

File tree

7 files changed

+42
-1
lines changed

7 files changed

+42
-1
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ pnpm dev
170170
通用:
171171

172172
- `AUTH_SECRET_KEY` 访问权限密钥,可选
173+
- `MAX_REQUEST_PER_HOUR` 每小时最大请求次数,可选,默认无限
173174
- `TIMEOUT_MS` 超时,单位毫秒,可选
174175
- `SOCKS_PROXY_HOST``SOCKS_PROXY_PORT` 一起时生效,可选
175176
- `SOCKS_PROXY_PORT``SOCKS_PROXY_HOST` 一起时生效,可选
@@ -224,6 +225,8 @@ services:
224225
API_REVERSE_PROXY: xxx
225226
# 访问权限密钥,可选
226227
AUTH_SECRET_KEY: xxx
228+
# 每小时最大请求次数,可选,默认无限
229+
MAX_REQUEST_PER_HOUR: 0
227230
# 超时,单位毫秒,可选
228231
TIMEOUT_MS: 60000
229232
# Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效
@@ -245,6 +248,7 @@ services:
245248
| --------------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
246249
| `PORT` | 必填 | 默认 `3002`
247250
| `AUTH_SECRET_KEY` | 可选 | 访问权限密钥 |
251+
| `MAX_REQUEST_PER_HOUR` | 可选 | 每小时最大请求次数,可选,默认无限 |
248252
| `TIMEOUT_MS` | 可选 | 超时时间,单位毫秒 |
249253
| `OPENAI_API_KEY` | `OpenAI API` 二选一 | 使用 `OpenAI API` 所需的 `apiKey` [(获取 apiKey)](https://platform.openai.com/overview) |
250254
| `OPENAI_ACCESS_TOKEN` | `Web API` 二选一 | 使用 `Web API` 所需的 `accessToken` [(获取 accessToken)](https://chat.openai.com/api/auth/session) |

docker-compose/docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ services:
1818
API_REVERSE_PROXY: xxx
1919
# 访问权限密钥,可选
2020
AUTH_SECRET_KEY: xxx
21+
# 每小时最大请求次数,可选,默认无限
22+
MAX_REQUEST_PER_HOUR: 0
2123
# 超时,单位毫秒,可选
2224
TIMEOUT_MS: 60000
2325
# Socks代理,可选,和 SOCKS_PROXY_PORT 一起时生效

service/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ SOCKS_PROXY_PORT=
2727

2828
# HTTPS PROXY
2929
HTTPS_PROXY=
30+
31+
# Rate Limit
32+
MAX_REQUEST_PER_HOUR=

service/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"dotenv": "^16.0.3",
3030
"esno": "^0.16.3",
3131
"express": "^4.18.2",
32+
"express-rate-limit": "^6.7.0",
3233
"https-proxy-agent": "^5.0.1",
3334
"isomorphic-fetch": "^3.0.0",
3435
"node-fetch": "^3.3.0",

service/pnpm-lock.yaml

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

service/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import express from 'express'
22
import type { ChatContext, ChatMessage } from './chatgpt'
33
import { chatConfig, chatReplyProcess, currentModel } from './chatgpt'
44
import { auth } from './middleware/auth'
5+
import { limiter } from './middleware/limiter'
56
import { isNotEmptyString } from './utils/is'
67

78
const app = express()
@@ -17,7 +18,7 @@ app.all('*', (_, res, next) => {
1718
next()
1819
})
1920

20-
router.post('/chat-process', auth, async (req, res) => {
21+
router.post('/chat-process', [auth, limiter], async (req, res) => {
2122
res.setHeader('Content-type', 'application/octet-stream')
2223

2324
try {

service/src/middleware/limiter.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { rateLimit } from 'express-rate-limit'
2+
import { isNotEmptyString } from '../utils/is'
3+
4+
const MAX_REQUEST_PER_HOUR = process.env.MAX_REQUEST_PER_HOUR
5+
6+
const maxCount = (isNotEmptyString(MAX_REQUEST_PER_HOUR) && !isNaN(Number(MAX_REQUEST_PER_HOUR)))
7+
? parseInt(MAX_REQUEST_PER_HOUR)
8+
: 0 // 0 means unlimited
9+
10+
const limiter = rateLimit({
11+
windowMs: 60 * 60 * 1000, // Maximum number of accesses within an hour
12+
max: maxCount,
13+
statusCode: 200, // 200 means success,but the message is 'Too many request from this IP in 1 hour'
14+
message: async (req, res) => {
15+
res.send({ status: 'Fail', message: 'Too many request from this IP in 1 hour', data: null })
16+
},
17+
})
18+
19+
export { limiter }

0 commit comments

Comments
 (0)