310 lines
6.8 KiB
Markdown
310 lines
6.8 KiB
Markdown
# Cloudflare Workers Runtime APIs
|
|
|
|
Key runtime APIs for Workers development.
|
|
|
|
## Fetch API
|
|
|
|
```typescript
|
|
// Subrequest
|
|
const response = await fetch('https://api.example.com/data', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ key: 'value' }),
|
|
cf: {
|
|
cacheTtl: 3600,
|
|
cacheEverything: true
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
```
|
|
|
|
## Headers API
|
|
|
|
```typescript
|
|
// Read headers
|
|
const userAgent = request.headers.get('User-Agent');
|
|
|
|
// Cloudflare-specific
|
|
const country = request.cf?.country;
|
|
const colo = request.cf?.colo;
|
|
const clientIP = request.headers.get('CF-Connecting-IP');
|
|
|
|
// Set headers
|
|
const headers = new Headers();
|
|
headers.set('Content-Type', 'application/json');
|
|
headers.append('X-Custom-Header', 'value');
|
|
```
|
|
|
|
## HTMLRewriter
|
|
|
|
```typescript
|
|
export default {
|
|
async fetch(request: Request): Promise<Response> {
|
|
const response = await fetch(request);
|
|
|
|
return new HTMLRewriter()
|
|
.on('title', {
|
|
element(element) {
|
|
element.setInnerContent('New Title');
|
|
}
|
|
})
|
|
.on('a[href]', {
|
|
element(element) {
|
|
const href = element.getAttribute('href');
|
|
element.setAttribute('href', href.replace('http://', 'https://'));
|
|
}
|
|
})
|
|
.transform(response);
|
|
}
|
|
};
|
|
```
|
|
|
|
## WebSockets
|
|
|
|
```typescript
|
|
export default {
|
|
async fetch(request: Request): Promise<Response> {
|
|
const upgradeHeader = request.headers.get('Upgrade');
|
|
if (upgradeHeader !== 'websocket') {
|
|
return new Response('Expected WebSocket', { status: 426 });
|
|
}
|
|
|
|
const pair = new WebSocketPair();
|
|
const [client, server] = Object.values(pair);
|
|
|
|
server.accept();
|
|
|
|
server.addEventListener('message', (event) => {
|
|
server.send(`Echo: ${event.data}`);
|
|
});
|
|
|
|
return new Response(null, {
|
|
status: 101,
|
|
webSocket: client
|
|
});
|
|
}
|
|
};
|
|
```
|
|
|
|
## Streams API
|
|
|
|
```typescript
|
|
const { readable, writable } = new TransformStream();
|
|
|
|
const writer = writable.getWriter();
|
|
writer.write(new TextEncoder().encode('chunk 1'));
|
|
writer.write(new TextEncoder().encode('chunk 2'));
|
|
writer.close();
|
|
|
|
return new Response(readable, {
|
|
headers: { 'Content-Type': 'text/plain' }
|
|
});
|
|
```
|
|
|
|
## Web Crypto API
|
|
|
|
```typescript
|
|
// Generate hash
|
|
const data = new TextEncoder().encode('message');
|
|
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
|
|
// HMAC signature
|
|
const key = await crypto.subtle.importKey(
|
|
'raw',
|
|
new TextEncoder().encode('secret'),
|
|
{ name: 'HMAC', hash: 'SHA-256' },
|
|
false,
|
|
['sign', 'verify']
|
|
);
|
|
|
|
const signature = await crypto.subtle.sign('HMAC', key, data);
|
|
const valid = await crypto.subtle.verify('HMAC', key, signature, data);
|
|
|
|
// Random values
|
|
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
|
|
const uuid = crypto.randomUUID();
|
|
```
|
|
|
|
## Encoding APIs
|
|
|
|
```typescript
|
|
// TextEncoder
|
|
const encoder = new TextEncoder();
|
|
const bytes = encoder.encode('Hello');
|
|
|
|
// TextDecoder
|
|
const decoder = new TextDecoder();
|
|
const text = decoder.decode(bytes);
|
|
|
|
// Base64
|
|
const base64 = btoa('Hello');
|
|
const decoded = atob(base64);
|
|
```
|
|
|
|
## URL API
|
|
|
|
```typescript
|
|
const url = new URL(request.url);
|
|
const hostname = url.hostname;
|
|
const pathname = url.pathname;
|
|
const search = url.search;
|
|
|
|
// Query parameters
|
|
const name = url.searchParams.get('name');
|
|
url.searchParams.set('page', '2');
|
|
url.searchParams.delete('old');
|
|
```
|
|
|
|
## FormData API
|
|
|
|
```typescript
|
|
// Parse form data
|
|
const formData = await request.formData();
|
|
const name = formData.get('name');
|
|
const file = formData.get('file');
|
|
|
|
// Create form data
|
|
const form = new FormData();
|
|
form.append('name', 'value');
|
|
form.append('file', blob, 'filename.txt');
|
|
```
|
|
|
|
## Response Types
|
|
|
|
```typescript
|
|
// Text
|
|
return new Response('Hello');
|
|
|
|
// JSON
|
|
return Response.json({ message: 'Hello' });
|
|
|
|
// Stream
|
|
return new Response(readable);
|
|
|
|
// Redirect
|
|
return Response.redirect('https://example.com', 302);
|
|
|
|
// Error
|
|
return new Response('Not Found', { status: 404 });
|
|
```
|
|
|
|
## Request Cloning
|
|
|
|
```typescript
|
|
// Clone for multiple reads
|
|
const clone = request.clone();
|
|
const body1 = await request.json();
|
|
const body2 = await clone.json();
|
|
```
|
|
|
|
## AbortController
|
|
|
|
```typescript
|
|
const controller = new AbortController();
|
|
const { signal } = controller;
|
|
|
|
setTimeout(() => controller.abort(), 5000);
|
|
|
|
try {
|
|
const response = await fetch('https://slow-api.com', { signal });
|
|
} catch (error) {
|
|
if (error.name === 'AbortError') {
|
|
console.log('Request timed out');
|
|
}
|
|
}
|
|
```
|
|
|
|
## Scheduling APIs
|
|
|
|
```typescript
|
|
// setTimeout
|
|
const timeoutId = setTimeout(() => {
|
|
console.log('Delayed');
|
|
}, 1000);
|
|
|
|
// setInterval
|
|
const intervalId = setInterval(() => {
|
|
console.log('Repeated');
|
|
}, 1000);
|
|
|
|
// Clear
|
|
clearTimeout(timeoutId);
|
|
clearInterval(intervalId);
|
|
```
|
|
|
|
## Console API
|
|
|
|
```typescript
|
|
console.log('Info message');
|
|
console.error('Error message');
|
|
console.warn('Warning message');
|
|
console.debug('Debug message');
|
|
|
|
// Structured logging
|
|
console.log(JSON.stringify({
|
|
level: 'info',
|
|
message: 'Request processed',
|
|
url: request.url,
|
|
timestamp: new Date().toISOString()
|
|
}));
|
|
```
|
|
|
|
## Performance API
|
|
|
|
```typescript
|
|
const start = performance.now();
|
|
await processRequest();
|
|
const duration = performance.now() - start;
|
|
console.log(`Processed in ${duration}ms`);
|
|
```
|
|
|
|
## Bindings Reference
|
|
|
|
### KV Operations
|
|
```typescript
|
|
await env.KV.put(key, value, { expirationTtl: 3600, metadata: { userId: '123' } });
|
|
const value = await env.KV.get(key, 'json');
|
|
const { value, metadata } = await env.KV.getWithMetadata(key);
|
|
await env.KV.delete(key);
|
|
const list = await env.KV.list({ prefix: 'user:' });
|
|
```
|
|
|
|
### D1 Operations
|
|
```typescript
|
|
const result = await env.DB.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();
|
|
const { results } = await env.DB.prepare('SELECT * FROM users').all();
|
|
await env.DB.prepare('INSERT INTO users (name) VALUES (?)').bind(name).run();
|
|
await env.DB.batch([stmt1, stmt2, stmt3]);
|
|
```
|
|
|
|
### R2 Operations
|
|
```typescript
|
|
await env.R2.put(key, value, { httpMetadata: { contentType: 'image/jpeg' } });
|
|
const object = await env.R2.get(key);
|
|
await env.R2.delete(key);
|
|
const list = await env.R2.list({ prefix: 'uploads/' });
|
|
const multipart = await env.R2.createMultipartUpload(key);
|
|
```
|
|
|
|
### Queue Operations
|
|
```typescript
|
|
await env.QUEUE.send({ type: 'email', to: 'user@example.com' });
|
|
await env.QUEUE.sendBatch([{ body: msg1 }, { body: msg2 }]);
|
|
```
|
|
|
|
### Workers AI
|
|
```typescript
|
|
const response = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
|
|
messages: [{ role: 'user', content: 'What is edge computing?' }]
|
|
});
|
|
```
|
|
|
|
## Resources
|
|
|
|
- Runtime APIs: https://developers.cloudflare.com/workers/runtime-apis/
|
|
- Web Standards: https://developers.cloudflare.com/workers/runtime-apis/web-standards/
|
|
- Bindings: https://developers.cloudflare.com/workers/runtime-apis/bindings/
|