Skip to content

Commit 11674fe

Browse files
committed
refactor: improve error handling in rate limit middleware to allow key generator and store errors to bubble up
1 parent c541f33 commit 11674fe

File tree

2 files changed

+84
-253
lines changed

2 files changed

+84
-253
lines changed

lib/middleware/rate-limit.js

Lines changed: 71 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -111,82 +111,50 @@ function createRateLimit(options = {}) {
111111
return next()
112112
}
113113

114-
try {
115-
const key = await keyGenerator(req)
116-
const {totalHits, resetTime} = await activeStore.increment(key, windowMs)
117-
118-
if (totalHits > max) {
119-
let response
120-
121-
// If a custom message is provided, use it as plain text
122-
if (message) {
123-
response = new Response(message, {status: 429})
124-
} else {
125-
response = await handler(req, totalHits, max, resetTime)
126-
if (typeof response === 'string') {
127-
response = new Response(response, {status: 429})
128-
}
114+
// Generate key and record the request immediately - let errors bubble up
115+
const key = await keyGenerator(req)
116+
const {totalHits, resetTime} = await activeStore.increment(key, windowMs)
117+
118+
// Check if rate limit exceeded
119+
if (totalHits > max) {
120+
let response
121+
122+
// If a custom message is provided, use it as plain text
123+
if (message) {
124+
response = new Response(message, {status: 429})
125+
} else {
126+
response = await handler(req, totalHits, max, resetTime)
127+
if (typeof response === 'string') {
128+
response = new Response(response, {status: 429})
129129
}
130-
131-
return addRateLimitHeaders(response, totalHits, resetTime)
132130
}
133131

134-
// Set rate limit context
135-
req.ctx = req.ctx || {}
136-
req.ctx.rateLimit = {
137-
limit: max,
138-
used: totalHits,
139-
remaining: Math.max(0, max - totalHits),
140-
resetTime,
141-
current: totalHits,
142-
reset: resetTime,
143-
}
144-
req.rateLimit = {
145-
limit: max,
146-
remaining: Math.max(0, max - totalHits),
147-
current: totalHits,
148-
reset: resetTime,
149-
}
132+
return addRateLimitHeaders(response, totalHits, resetTime)
133+
}
150134

151-
const response = await next()
152-
if (response instanceof Response) {
153-
return addRateLimitHeaders(response, totalHits, resetTime)
154-
}
155-
return response
156-
} catch (error) {
157-
// If key generation fails, fallback to a default key
158-
try {
159-
const key = 'unknown'
160-
const {totalHits, resetTime} = await activeStore.increment(
161-
key,
162-
windowMs,
163-
)
164-
165-
req.ctx = req.ctx || {}
166-
req.ctx.rateLimit = {
167-
limit: max,
168-
used: totalHits,
169-
remaining: Math.max(0, max - totalHits),
170-
resetTime,
171-
current: totalHits,
172-
reset: resetTime,
173-
}
174-
req.rateLimit = {
175-
limit: max,
176-
remaining: Math.max(0, max - totalHits),
177-
current: totalHits,
178-
reset: resetTime,
179-
}
135+
// Set rate limit context
136+
req.ctx = req.ctx || {}
137+
req.ctx.rateLimit = {
138+
limit: max,
139+
used: totalHits,
140+
remaining: Math.max(0, max - totalHits),
141+
resetTime,
142+
current: totalHits,
143+
reset: resetTime,
144+
}
145+
req.rateLimit = {
146+
limit: max,
147+
remaining: Math.max(0, max - totalHits),
148+
current: totalHits,
149+
reset: resetTime,
150+
}
180151

181-
const response = await next()
182-
if (response instanceof Response) {
183-
return addRateLimitHeaders(response, totalHits, resetTime)
184-
}
185-
return response
186-
} catch (e) {
187-
return next()
188-
}
152+
// Continue with request processing - let any errors bubble up
153+
const response = await next()
154+
if (response instanceof Response) {
155+
return addRateLimitHeaders(response, totalHits, resetTime)
189156
}
157+
return response
190158
}
191159
}
192160

@@ -253,47 +221,43 @@ function createSlidingWindowRateLimit(options = {}) {
253221
const requests = new Map() // key -> array of timestamps
254222

255223
return async function slidingWindowRateLimitMiddleware(req, next) {
256-
try {
257-
const key = await keyGenerator(req)
258-
const now = Date.now()
259-
260-
// Get existing requests for this key
261-
let userRequests = requests.get(key) || []
224+
// Generate key and record the request immediately - let errors bubble up
225+
const key = await keyGenerator(req)
226+
const now = Date.now()
262227

263-
// Remove old requests outside the window
264-
userRequests = userRequests.filter(
265-
(timestamp) => now - timestamp < windowMs,
228+
// Get existing requests for this key
229+
let userRequests = requests.get(key) || []
230+
231+
// Remove old requests outside the window
232+
userRequests = userRequests.filter(
233+
(timestamp) => now - timestamp < windowMs,
234+
)
235+
236+
// Check if limit exceeded
237+
if (userRequests.length >= max) {
238+
const response = await handler(
239+
req,
240+
userRequests.length,
241+
max,
242+
new Date(now + windowMs),
266243
)
244+
return response
245+
}
267246

268-
// Check if limit exceeded
269-
if (userRequests.length >= max) {
270-
const response = await handler(
271-
req,
272-
userRequests.length,
273-
max,
274-
new Date(now + windowMs),
275-
)
276-
return response
277-
}
278-
279-
// Add current request
280-
userRequests.push(now)
281-
requests.set(key, userRequests)
282-
283-
// Add rate limit info to context
284-
req.ctx = req.ctx || {}
285-
req.ctx.rateLimit = {
286-
limit: max,
287-
used: userRequests.length,
288-
remaining: max - userRequests.length,
289-
resetTime: new Date(userRequests[0] + windowMs),
290-
}
291-
292-
return next()
293-
} catch (error) {
294-
console.error('Sliding window rate limiting error:', error)
295-
return next()
247+
// Add current request
248+
userRequests.push(now)
249+
requests.set(key, userRequests)
250+
251+
// Add rate limit info to context
252+
req.ctx = req.ctx || {}
253+
req.ctx.rateLimit = {
254+
limit: max,
255+
used: userRequests.length,
256+
remaining: max - userRequests.length,
257+
resetTime: new Date(userRequests[0] + windowMs),
296258
}
259+
260+
return next()
297261
}
298262
}
299263

0 commit comments

Comments
 (0)