Return HTML from Worker with Hono framework
To return an HTML page from a Cloudflare Worker using the Hono framework, import Hono and the html template tag from 'hono/html'. Create an app instance, define a route with app.get(), and use the html template tag to create the HTML document. Call c.html(doc) to return the response.
Stream large JSON to avoid 128 MB memory limit
The Streams API allows you to process JSON payloads that would exceed a Worker's 128 MB memory limit if fully buffered. Streaming allows parsing and transforming JSON data incrementally as it arrives, which is faster than buffering the entire payload into memory. This enables Workers to handle multi-gigabyte payloads or files within memory limits.
WebSocketPair creates bidirectional connection
Create a new instance of WebSocketPair, which contains server and client WebSockets accessed via keys 0 and 1 or using Object.values() with destructuring. Return the client WebSocket in a Response with HTTP 101 status code to indicate protocol switching, while handling the server WebSocket in your Workers function.
WebSocket server upgrade header check
When an incoming WebSocket request reaches the Workers function, it will contain an Upgrade header set to 'websocket'. Check for this header and return a 426 status code if it is missing or not equal to 'websocket'.
WebSocket server.accept() keeps connection open
Call accept() on the server WebSocket to tell the Workers runtime to listen for WebSocket data and keep the connection open with the client WebSocket.
WebSocket event listeners for message handling
WebSockets emit events that can be connected to using addEventListener. The message event is used to receive data from the WebSocket connection.
WebSocket client creation with URL
Create a WebSocket client in the browser by instantiating a new WebSocket object with the URL for the Workers function: const websocket = new WebSocket('wss://example.workers.dev'). Attach event listeners such as 'message' to handle server responses.
WebSocket client send and close methods
WebSocket clients can send messages back to the server using the send() function with websocket.send('MESSAGE'). Close the connection using websocket.close().
WebSocket client connection from Workers using fetch
Cloudflare Workers can establish a WebSocket connection to a remote server by making a fetch request with the Upgrade: websocket header. The Workers Runtime automatically handles other WebSocket protocol requirements like the Sec-WebSocket-Key header. If the handshake succeeds, the response has a webSocket property.
WebSocket client accept() for handling in JavaScript
When a Worker establishes a WebSocket connection via fetch, call accept() on the WebSocket to indicate that it will be handled in JavaScript rather than returned to a client. Use accept({ allowHalfOpen: true }) if you need to coordinate the close handshake manually, such as when proxying.
WebSocket auto-reply to close with web_socket_auto_reply_to_close flag
The web_socket_auto_reply_to_close compatibility flag (enabled by default on compatibility dates on or after 2026-04-07) makes the Workers runtime automatically reply to incoming Close frames and transition readyState to CLOSED before firing the close event. You do not need to call close() in your close event handler. For half-open behavior, pass { allowHalfOpen: true } to accept().
JavaScript WebSocket server example
Example WebSocket server in JavaScript that checks for Upgrade header, creates WebSocketPair, accepts server connection, and listens for messages:
```js
async function handleRequest(request) {
const upgradeHeader = request.headers.get('Upgrade');
if (!upgradeHeader || upgradeHeader !== 'websocket') {
return new Response('Expected Upgrade: websocket', { status: 426 });
}
const webSocketPair = new WebSocketPair();
const [client, server] = Object.values(webSocketPair);
server.accept();
server.addEventListener('message', event => {
console.log(event.data);
});
return new Response(null, {
status: 101,
webSocket: client,
});
}
```
Rust WebSocket server example
Example WebSocket server in Rust that checks for Upgrade header, creates WebSocketPair, accepts server connection, and streams messages:
```rs
use futures::StreamExt;
use worker::*;
#[event(fetch)]
async fn fetch(req: HttpRequest, _env: Env, _ctx: Context) -> Result<worker::Response> {
let upgrade_header = match req.headers().get("Upgrade") {
Some(h) => h.to_str().unwrap(),
None => "",
};
if upgrade_header != "websocket" {
return worker::Response::error("Expected Upgrade: websocket", 426);
}
let ws = WebSocketPair::new()?;
let client = ws.client;
let server = ws.server;
server.accept()?;
wasm_bindgen_futures::spawn_local(async move {
let mut event_stream = server.events().expect("could not open stream");
while let Some(event) = event_stream.next().await {
match event.expect("received error in websocket") {
WebsocketEvent::Message(msg) => server.send(&msg.text()).unwrap(),
WebsocketEvent::Close(event) => console_log!("{:?}", event),
}
}
});
worker::Response::from_websocket(client)
}
```
Hono WebSocket server example
Example WebSocket server using Hono framework:
```ts
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'
const app = new Hono()
app.get(
'*',
upgradeWebSocket((c) => {
return {
onMessage(event, ws) {
console.log('Received message from client:', event.data)
ws.send(`Echo: ${event.data}`)
},
onClose: () => {
console.log('WebSocket closed:', event)
},
onError: () => {
console.error('WebSocket error:', event)
},
}
})
)
export default app;
```
JavaScript WebSocket client example
Example WebSocket client that creates a connection and listens for messages:
```js
const websocket = new WebSocket(
"wss://websocket-example.signalnerve.workers.dev",
);
websocket.addEventListener("message", (event) => {
console.log("Message received from server");
console.log(event.data);
});
```
JavaScript WebSocket fetch-based client example
Example of establishing a WebSocket connection from a Worker via fetch request with Upgrade header:
```js
async function websocket(url) {
let resp = await fetch(url, {
headers: {
Upgrade: "websocket",
},
});
let ws = resp.webSocket;
if (!ws) {
throw new Error("server didn't accept WebSocket");
}
ws.accept();
ws.send("hello");
ws.addEventListener("message", (msg) => {
console.log(msg.data);
});
}
```
Additional event handlers beyond fetch
In addition to the fetch handler, you can define additional event handlers in the exported object. For example, add a scheduled() handler to respond to Worker invocations via a Cron Trigger.
Worker fetch handler exports and parameters
A Worker must have a default export of an object with properties corresponding to events to handle. The fetch() handler is called when the Worker receives an HTTP request. The fetch handler is passed three parameters: request, env, and context. The fetch handler must return a Response object or a Promise which resolves with a Response object.
Basic Worker example code
A minimal Worker that exports a fetch handler and returns a Hello message looks like this:
export default {
async fetch(request, env, ctx) {
return new Response("Hello World!");
},
};
POST request example in Python Workers
Example of handling a POST request that parses JSON from the request body and returns a personalized response:
from workers import WorkerEntrypoint, Response
from hello import hello
class Default(WorkerEntrypoint):
async def fetch(self, request):
body = await request.json()
name = body["name"]
return Response(hello(name))
Can be tested with: curl --header "Content-Type: application/json" --request POST --data '{"name": "Python"}' http://localhost:8787
Fetch handler in Python Workers
A Python Worker's main entry point is the fetch handler, implemented as an async method in a Default class that extends WorkerEntrypoint. The fetch method receives a request parameter and returns a Response. A minimal Python Worker consists of: from workers import WorkerEntrypoint, Response
class Default(WorkerEntrypoint):
async def fetch(self, request):
return Response("Hello World!")
Request object in Python Workers
The request parameter passed to the fetch handler is a JavaScript Request object exposed via the foreign function interface (FFI), allowing direct access from Python code. Methods like await request.json() can be called within an async function to parse the request body as JSON.
Parse JSON from incoming request in Python Worker
Call await request.json() on the request object to parse the request body as JSON. This returns a native Python dictionary that can be accessed immediately. For example: body = await request.json(); name = body["name"].
Return JSON response from Python Worker
Use Response.json(data) to return a JSON response from a Python Worker, passing a Python dictionary or other JSON-serializable object. For example: Response.json({"greeting": "Hello, World!", "status": "ok"}).
Fetch handler parameters in Rust Workers
The fetch handler in workers-rs provides three arguments: Request (object representing the incoming request with methods for headers, method, path, Cloudflare properties, and body access), Env (provides access to Worker bindings), and Context (provides access to waitUntil and passThroughOnException functionality).
Two concepts in Workers development: Worker execution and Bindings
Worker execution refers to where Worker code runs (local machine vs Cloudflare infrastructure). Bindings are how Workers interact with Cloudflare resources like KV, R2, D1, Queues, and Durable Objects, accessed via the env object (such as env.MY_KV).
request.cf in module syntax Workers
As of 2021-06-04, request.cf is no longer missing when writing Workers using module syntax.
HTTP method case insensitivity
As of 2020-07-09, common HTTP method names passed to fetch() or new Request() are case-insensitive as required by the Fetch API spec.
Response.json static method
As of 2022-05-26, the static Response.json() method can be used to initialize a Response object with a JSON-serialized payload.
Response.redirect slash coalescing
As of 2022-05-05, Response.redirect(url) will no longer coalesce multiple consecutive slash characters appearing in the URL's path.
ScheduledEvent.cron property
As of 2021-04-19, ScheduledEvent.cron is set to the original cron string the event was scheduled for.
Module Workers waitUntil support
As of 2021-04-19, waitUntil is supported for module Workers. An additional 'ctx' argument is passed after 'env', and waitUntil is a method on ctx.
Module Workers passThroughOnException
As of 2021-04-19, passThroughOnException is available under the ctx argument to module handlers.
readyState property on ReadableStream
As of 2021-10-14, request.signal always returns an AbortSignal.
fetch() runtime behavior with cache
In the context of Workers, fetch() provided by the runtime communicates with the Cloudflare cache. First, fetch() checks to see if the URL matches a different zone. If it does, it reads through that zone's cache (or Worker). Otherwise, it reads through its own zone's cache, even if the URL is for a non-Cloudflare site. Cache settings on fetch() automatically apply caching rules based on your Cloudflare settings. fetch() does not allow you to modify or inspect objects before they reach the cache, but does allow you to modify how it will cache. When a response fills the cache, the response header contains CF-Cache-Status: HIT.
HTTP/HTTPS inbound handling with fetch handler
Cloudflare Workers handle incoming HTTP requests using the fetch() handler.
HTTP/HTTPS outbound with fetch API
Cloudflare Workers make HTTP subrequests using the fetch() API.
WebSockets inbound with WebSocket API
Cloudflare Workers can accept incoming WebSocket connections using the WebSocket API.
HTTP/3 QUIC inbound requests
Cloudflare Workers accept inbound requests over HTTP/3 by enabling it on your zone in Speed > Settings > Protocol Optimization area of the Cloudflare dashboard.
waitUntil does not block response
The waitUntil command extends the lifetime of the fetch event and accepts a Promise-based task that the Workers runtime will execute before the handler terminates, but without blocking the response. It is ideal for caching responses or handling logging.
waitUntil in ES modules uses context parameter
In ES modules format, waitUntil is available on the context parameter object passed to handlers: ctx.waitUntil(promise). In Service Worker format, it is accessed via event.waitUntil().
passThroughOnException in ES modules uses context parameter
In ES modules format, passThroughOnException is available on the context parameter object: ctx.passThroughOnException(). In Service Worker format, it is accessed via event.passThroughOnException().
Service Worker FetchEvent properties
FetchEvent object provides the following properties: event.type (string, always 'fetch'), event.request (Request object for incoming HTTP request), event.respondWith(response|Promise) (intercepts request to send custom response), event.waitUntil(promise) (extends event lifetime), event.passThroughOnException() (prevents runtime error on unhandled exception).
respondWith behavior when not called
If a fetch event handler does not call respondWith, the runtime delivers the event to the next registered fetch event handler. If no fetch event handler calls respondWith, the runtime forwards the request to the origin. However, if there is no origin or the Worker is the origin server (true for *.workers.dev domains), respondWith must be called for a valid response.
passThroughOnException prevents runtime error response
The passThroughOnException method prevents a runtime error response when the Worker throws an unhandled exception. Instead, the script fails open and proxies the request to the origin server as though the Worker was never invoked.
Modules worker script structure with fetch and scheduled handlers
A modules format worker exports a default object with async fetch and/or scheduled handlers. The fetch handler receives `request`, `env` (containing bindings, KV namespaces, Durable Objects), and `ctx` (with `waitUntil` and `passThroughOnException` methods). The scheduled handler receives `controller` (with `scheduledTime` and `cron` properties), `env`, and `ctx` (with `waitUntil` method).
WebSocketPair for bidirectional communication
Use new WebSocketPair() to create a client and server end of a WebSocket connection. Object.values() returns the pair as an array. The server end can call accept(), addEventListener(), and send() to handle messages.
Echo WebSocket server example
This example shows a complete WebSocket echo server in a Worker: create a WebSocketPair, accept the server end, listen for message events, and echo data back using send():
export default {
fetch(request) {
const [client, server] = Object.values(new WebSocketPair());
server.accept();
server.addEventListener("message", (event) => {
server.send(event.data);
});
return new Response(null, {
status: 101,
webSocket: client,
});
},
};
WebSocket upgrade with status 101 in Workers
A Worker must respond with HTTP status 101 (Switching Protocols) and include a webSocket property on the Response object to upgrade a connection to WebSocket. The response body should be null.
Response#waitUntil() method not supported in Miniflare v3
The Response#waitUntil() method is not supported in Miniflare v3. workerd does not support waiting for all waitUntil()ed promises yet.
Workers request/response pattern with fetch handler
All incoming HTTP requests to a Worker are passed to the fetch() handler as a request object. After a request is received, the Worker constructs and returns a response to the client. The default handler structure is: export default { async fetch(request, env, ctx) { return new Response('Hello World!'); } }. Workers serve responses directly from Cloudflare's global network instead of routing to an origin server.
Handling PUT requests in Workers
Check request method with request.method === 'PUT'. Retrieve request body with await request.text() and parse it. Return a Response with status code and body. Wrap body parsing in try...catch to handle errors and return appropriate HTTP status codes.
Serving HTML responses from Workers
Create an HTML response by returning new Response(html, { headers: { 'Content-Type': 'text/html' } }). HTML content can be a static string or dynamically generated function. Pass data to client-side JavaScript by embedding it in script tags using template literals.
Parse JSON request body with request.json()
To parse an incoming request body as JSON in a Worker, use: const data = await request.json();. This returns a promise that resolves to the parsed JSON object.
Set Content-Type response header for SVG
When returning SVG content from a Worker, set the Content-Type header to 'image/svg+xml' to allow browsers to properly parse the data as an image. Example: new Response(svgData, { headers: { 'Content-Type': 'image/svg+xml' } })
Set Content-Type header for HTML responses
When returning HTML content from a Worker, set the Content-Type header to 'text/html'. Example: new Response(htmlString, { headers: { 'Content-Type': 'text/html' } })
Fetch event handler signature
Cloudflare Workers applications listen for fetch events. The fetch handler receives three parameters: request, env, and ctx. The handler must return a Response object. Example: export default { async fetch(request, env, ctx) { return new Response('Hello Worker!'); } };
HTTP 405 status for non-POST requests
When a Worker should only accept POST requests, return a Response with status code 405 for any incoming request that is not a POST, using syntax: new Response('Expected POST request', { status: 405 })
Access GitHub webhook event type from header
The GitHub webhook event type (such as 'push', 'pull_request', etc.) is available in the `X-GitHub-Event` header of the webhook request.
Example Worker fetch handler for webhook processing
export default {
async fetch(request, env, ctx) {
if(request.method !== 'POST') {
return new Response('Please send a POST request!');
}
try {
const rawBody = await request.text();
if (!checkSignature(rawBody, request.headers, env.GITHUB_SECRET_TOKEN)) {
return new Response('Wrong password, try again', {status: 403});
}
const action = request.headers.get('X-GitHub-Event');
const json = JSON.parse(rawBody);
const repoName = json.repository.full_name;
const senderName = json.sender.login;
return await sendText(
env.TWILIO_ACCOUNT_SID,
env.TWILIO_AUTH_TOKEN,
`${senderName} completed ${action} onto your repo ${repoName}`
);
} catch (e) {
return new Response(`Error: ${e}`);
}
},
};
This example shows a complete webhook handler that validates the request, checks the GitHub signature, and processes the webhook event.