Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,9 @@

```javascript
// functions/_middleware.js (global) or functions/users/_middleware.js (scoped to /users/*)

// Single
export async function onRequest(context) {
try {
return await context.next();
} catch (err) {
return new Response(`${err.message}\n${err.stack}`, { status: 500 });
}
try { return await context.next(); }
catch (err) { return new Response(`${err.message}\n${err.stack}`, { status: 500 }); }
}

// Chained (runs in array order)
Expand All @@ -24,14 +19,11 @@ export const onRequest = [errorHandling, authentication, logging];
async function authMiddleware(context: EventContext<Env>) {
const token = context.request.headers.get('authorization')?.replace('Bearer ', '');
if (!token) return new Response('Unauthorized', { status: 401 });

const session = await context.env.KV.get(`session:${token}`);
if (!session) return new Response('Invalid token', { status: 401 });

context.data.user = JSON.parse(session);
return context.next();
}

export const onRequest = [authMiddleware];
```

Expand All @@ -44,11 +36,9 @@ const corsHeaders = {
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
};

export async function onRequestOptions(context) {
export async function onRequestOptions() {
return new Response(null, { headers: corsHeaders });
}

export async function onRequest(context) {
const response = await context.next();
Object.entries(corsHeaders).forEach(([k, v]) => response.headers.set(k, v));
Expand All @@ -59,15 +49,12 @@ export async function onRequest(context) {
## Rate Limiting

```typescript
interface Env { RATE_LIMIT: KVNamespace; }

// Env: { RATE_LIMIT: KVNamespace }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The interface Env declaration was changed to a comment. While this reduces line count, it removes the actual type definition. For better code example integrity and to maintain a concise yet functional documentation structure, consider compressing the interface into a single line, similar to how interface Env { ASSETS: Fetcher; KV: KVNamespace; } was handled later in the document (line 120), rather than commenting it out entirely.

Suggested change
// Env: { RATE_LIMIT: KVNamespace }
interface Env { RATE_LIMIT: KVNamespace; }
References
  1. Maintain a tiered documentation structure with a concise core file. Compressing code examples helps keep the core file brief while maintaining technical accuracy.

async function rateLimitMiddleware(context: EventContext<Env>) {
const clientIP = context.request.headers.get('CF-Connecting-IP') || 'unknown';
const key = `ratelimit:${clientIP}`;
const count = parseInt(await context.env.RATE_LIMIT.get(key) || '0');

if (count >= 100) return new Response('Rate limit exceeded', { status: 429 });

await context.env.RATE_LIMIT.put(key, (count + 1).toString(), { expirationTtl: 3600 });
return context.next();
}
Expand All @@ -78,17 +65,12 @@ async function rateLimitMiddleware(context: EventContext<Env>) {
```typescript
export async function onRequestPost(context) {
const contentType = context.request.headers.get('content-type') || '';

if (contentType.includes('application/json')) {
const data = await context.request.json();
return Response.json({ received: data });
return Response.json({ received: await context.request.json() });
}

if (contentType.includes('application/x-www-form-urlencoded')) {
const formData = await context.request.formData();
return Response.json({ received: Object.fromEntries(formData) });
return Response.json({ received: Object.fromEntries(await context.request.formData()) });
}

if (contentType.includes('multipart/form-data')) {
const formData = await context.request.formData();
const file = formData.get('file') as File;
Expand All @@ -97,7 +79,6 @@ export async function onRequestPost(context) {
return Response.json({ uploaded: file.name });
}
}

return new Response('Unsupported content type', { status: 400 });
}
```
Expand All @@ -108,14 +89,12 @@ export async function onRequestPost(context) {
export async function onRequest(context) {
const cache = caches.default;
const cacheKey = new Request(context.request.url, context.request);

let response = await cache.match(cacheKey);
if (!response) {
response = new Response('Hello World');
response.headers.set('Cache-Control', 'public, max-age=3600');
context.waitUntil(cache.put(cacheKey, response.clone()));
}

return response;
}
```
Expand All @@ -125,41 +104,24 @@ export async function onRequest(context) {
```typescript
export async function onRequest(context) {
const url = new URL(context.request.url);

if (url.pathname === '/old-page') {
return Response.redirect(`${url.origin}/new-page`, 301);
}

if (url.protocol === 'http:') {
url.protocol = 'https:';
return Response.redirect(url.toString(), 301);
}

if (url.pathname === '/old-page') return Response.redirect(`${url.origin}/new-page`, 301);
if (url.protocol === 'http:') { url.protocol = 'https:'; return Response.redirect(url.toString(), 301); }
return context.next();
}
```

## Advanced Mode (`_worker.js`)

Replace `/functions` with `_worker.js` for full routing control (complex Workers, framework-generated output: Next.js, SvelteKit).
Replace `/functions` with `_worker.js` for full routing control (complex Workers, framework output: Next.js, SvelteKit).

```typescript
// Module Worker syntax required; /functions ignored when _worker.js present
// Manually call env.ASSETS.fetch() for static files; passThroughOnException() unavailable

interface Env {
ASSETS: Fetcher;
KV: KVNamespace;
}

interface Env { ASSETS: Fetcher; KV: KVNamespace; }
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);

if (url.pathname.startsWith('/api/')) {
return new Response('API response');
}

if (url.pathname.startsWith('/api/')) return new Response('API response');
return env.ASSETS.fetch(request);
}
} satisfies ExportedHandler<Env>;
Expand Down
Loading