These templates are simple building blocks for developing Workers scripts.
Simple Hello World in JS
wrangler generate my-app
https://github.com/cloudflare/worker-template
Simple Hello World in Rust
wrangler generate my-app
https://github.com/cloudflare/rustwasm-worker-template
Selects the logic based on the request
method and URL. Use with REST APIs or apps that require routing logic.
wrangler generate my-app
https://github.com/cloudflare/worker-template-router
Simple Hello World in TypeScript
wrangler generate my-app
https://github.com/EverlastingBugstopper/worker-typescript-template
Set up an A/B test by controlling what response is served based on cookies
async function handleRequest(request) {
const NAME = 'experiment-0'
// Responses below are place holders, you could set up
// a custom path for each test (e.g. /control/somepath )
const TEST_RESPONSE = new Response('Test group') // fetch('/test/sompath', request)
const CONTROL_RESPONSE = new Response('Control group') // fetch('/control/sompath', request)
// Determine which group this requester is in.
const cookie = request.headers.get('cookie')
if (cookie && cookie.includes(`${NAME}=control`)) {
return CONTROL_RESPONSE
} else if (cookie && cookie.includes(`${NAME}=test`)) {
return TEST_RESPONSE
} else {
// if no cookie then this is a new client, decide a group and set the cookie
let group = Math.random() < 0.5 ? 'test' : 'control' // 50/50 split
let response = group === 'control' ? CONTROL_RESPONSE : TEST_RESPONSE
response.headers.append('Set-Cookie', `${NAME}=${group}; path=/`)
return response
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
Sends two GET request to two urls and aggregates the responses into one response.
async function handleRequest(request) {
const init = {
headers: {
'content-type': type,
},
}
const responses = await Promise.all([fetch(url1, init), fetch(url2, init)])
const results = await Promise.all([gatherResponse(responses[0]), gatherResponse(responses[1])])
return new Response(results, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
/**
* gatherResponse awaits and returns a response body as a string.
* Use await gatherResponse(..) in an async function to get the response body
* @param {Response} response
*/
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}
/**
* Example someHost is set up to return JSON responses
* Replace url1 and url2 with the hosts you wish to
* send requests to
* @param {string} url the URL to send the request to
*/
const someHost = 'https://workers-tooling.cf/demos'
const url1 = someHost + '/requests/json'
const url2 = someHost + '/requests/json'
const type = 'application/json;charset=UTF-8'
Change the headers sent in a request or returned in a response
async function handleRequest(request) {
// Make the headers mutable by re-constructing the Request.
request = new Request(request)
request.headers.set('x-my-header', 'custom value')
const URL = 'https://workers-tooling.cf/demos/static/html'
// URL is set up to respond with dummy HTML, remove to send requests to your own origin
let response = await fetch(URL, request)
// Make the headers mutable by re-constructing the Response.
response = new Response(response.body, response)
response.headers.set('x-my-header', 'custom value')
return response
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
Allow or deny a request based on a known pre-shared key in a header. Note while this simple implementation is helpful, it is not meant to replace more secure scripts such as signed requests using the WebCrypto API.
async function handleRequest(request) {
let psk = request.headers.get(PRESHARED_AUTH_HEADER_KEY)
if (psk === PRESHARED_AUTH_HEADER_VALUE) {
// Correct preshared header key supplied. Fetching request
// from origin
return fetch(request)
}
// Incorrect key rejecting request
return new Response('Sorry, you have supplied an invalid key.', {
status: 403,
})
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
/**
* @param {string} PRESHARED_AUTH_HEADER_KEY custom header to check for key
* @param {string} PRESHARED_AUTH_HEADER_VALUE hard coded key value
*/
const PRESHARED_AUTH_HEADER_KEY = 'X-Custom-PSK'
const PRESHARED_AUTH_HEADER_VALUE = 'mypresharedkey'
Redirects requests to certain URLs based a mapped object to the request’s URL.
async function handleRequest(request) {
let requestURL = new URL(request.url)
let path = requestURL.pathname.split('/redirect')[1]
let location = redirectMap.get(path)
if (location) {
return Response.redirect(location, 301)
}
// If in map, return the original request
return fetch(request)
}
addEventListener('fetch', async event => {
event.respondWith(handleRequest(event.request))
})
const externalHostname = 'workers-tooling.cf'
const redirectMap = new Map([
['/bulk1', 'https://' + externalHostname + '/redirect2'],
['/bulk2', 'https://' + externalHostname + '/redirect3'],
['/bulk3', 'https://' + externalHostname + '/redirect4'],
['/bulk4', 'https://google.com'],
])
Cache using Cloudflare’s Cache API. This example can cache POST requests as well as change what hostname to store a response in cache. Note the previewer is not avalible for using Cache API.
async function handleRequest(event) {
let request = event.request
let cacheUrl = new URL(request.url)
// hostname for a different zone
cacheUrl.hostname = someOtherHostname
let cacheKey = new Request(cacheUrl, request)
let cache = caches.default
// Get this request from this zone's cache
let response = await cache.match(cacheKey)
if (!response) {
//if not in cache, grab it from the origin
response = await fetch(request)
// must use Response constructor to inherit all of response's fields
response = new Response(response.body, response)
// Cache API respects Cache-Control headers, so by setting max-age to 10
// the response will only live in cache for max of 10 seconds
response.headers.append('Cache-Control', 'max-age=10')
// store the fetched response as cacheKey
// use waitUntil so computational expensive tasks don't delay the response
event.waitUntil(cache.put(cacheKey, response.clone()))
}
return response
}
async function handlePostRequest(event) {
let request = event.request
let body = await request.clone().text()
let hash = await sha256(body)
let cacheUrl = new URL(request.url)
// get/store the URL in cache by prepending the body's hash
cacheUrl.pathname = '/posts' + cacheUrl.pathname + hash
// Convert to a GET to be able to cache
let cacheKey = new Request(cacheUrl, {
headers: request.headers,
method: 'GET',
})
let cache = caches.default
//try to find the cache key in the cache
let response = await cache.match(cacheKey)
// otherwise, fetch response to POST request from origin
if (!response) {
response = await fetch(request)
event.waitUntil(cache.put(cacheKey, response))
}
return response
}
addEventListener('fetch', event => {
try {
let request = event.request
if (request.method.toUpperCase() === 'POST')
return event.respondWith(handlePostRequest(event))
return event.respondWith(handleRequest(event))
} catch (e) {
return event.respondWith(new Response('Error thrown ' + e.message))
}
})
async function sha256(message) {
// encode as UTF-8
const msgBuffer = new TextEncoder().encode(message)
// hash the message
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer)
// convert ArrayBuffer to Array
const hashArray = Array.from(new Uint8Array(hashBuffer))
// convert bytes to hex string
const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('')
return hashHex
}
const someOtherHostname = 'my.herokuapp.com'
Determine how/if Cloudflare’s Classic CDN and Browsers will cache a resource by setting TTLs, cache keys, and cache settings.
async function handleRequest(request) {
let url = new URL(request.url)
// Only use the path for the cache key, removing query strings
// and always storing HTTPS e.g. https://www.example.com/file-uri-here
let someCustomKey = `https://${url.hostname}${url.pathname}`
let response = await fetch(request, {
cf: {
// Tell Cloudflare's Global CDN to always cache this fetch regardless of content type
// for a max of 5 seconds before revalidating the resource
cacheTtl: 5, // sets TTL to 5 and cacheEverything setting
//Enterprise only feature, see Cache API for other plans
cacheKey: someCustomKey,
},
})
// must use Response constructor to inherit all of response's fields
response = new Response(response.body, response)
//Set cache control headers to cache on browser for 25 minutes
response.headers.set('Cache-Control', 'max-age=1500')
return response
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
Return a response based on the incoming request’s URL, HTTP method, User Agent, IP address, ASN or device type (e.g. mobile)
const BLOCKED_HOSTNAMES = ['nope.mywebsite.com', 'bye.website.com']
async function handleRequest(request) {
// Return a new Response based on..
// On URL's hostname
let url = new URL(request.url)
if (BLOCKED_HOSTNAMES.includes(url.hostname)) {
return new Response('Blocked Host', { status: 403 })
}
// On URL's file extenstion (e.g. block paths ending in .doc or .xml)
let forbiddenExtRegExp = new RegExp(/\.(doc|xml)$/)
if (forbiddenExtRegExp.test(url.pathname)) {
return new Response('Blocked Extension', { status: 403 })
}
// On HTTP method
if (request.method === 'POST') {
return new Response('Response for POST')
}
// On User Agent
let userAgent = request.headers.get('User-Agent') || ''
if (userAgent.includes('bot')) {
return new Response('Block User Agent containing bot', { status: 403 })
}
// On Client's IP address
let clientIP = request.headers.get('CF-Connecting-IP')
if (clientIP === '1.2.3.4') {
return new Response('Block the IP 1.2.3.4', { status: 403 })
}
// On ASN
if ((request.cf || {}).asn == 64512) {
return new Response('Block the ASN 64512 response')
}
// On Device Type
// Requires Enterprise "CF-Device-Type Header" zone setting or
// Page Rule with "Cache By Device Type" setting applied.
let device = request.headers.get('CF-Device-Type')
if (device === 'mobile') {
return Response.redirect('https://mobile.example.com')
}
console.error(
"Getting Client's IP address, device type, and ASN are not supported in playground. Must test on a live worker",
)
return fetch(request)
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
Add necessary CORS headers to a third party API response
async function handleRequest(request) {
const url = new URL(request.url)
const apiurl = url.searchParams.get('apiurl')
// Rewrite request to point to API url. This also makes the request mutable
// so we can add the correct Origin header to make the API server think
// that this request isn't cross-site.
request = new Request(apiurl, request)
request.headers.set('Origin', new URL(apiurl).origin)
let response = await fetch(request)
// Recreate the response so we can modify the headers
response = new Response(response.body, response)
// Set CORS headers
response.headers.set('Access-Control-Allow-Origin', url.origin)
// Append to/Add Vary header so browser will cache response correctly
response.headers.append('Vary', 'Origin')
return response
}
function handleOptions(request) {
// Make sure the necesssary headers are present
// for this to be a valid pre-flight request
if (
request.headers.get('Origin') !== null &&
request.headers.get('Access-Control-Request-Method') !== null &&
request.headers.get('Access-Control-Request-Headers') !== null
) {
// Handle CORS pre-flight request.
// If you want to check the requested method + headers
// you can do that here.
return new Response(null, {
headers: corsHeaders,
})
} else {
// Handle standard OPTIONS request.
// If you want to allow other HTTP Methods, you can do that here.
return new Response(null, {
headers: {
Allow: 'GET, HEAD, POST, OPTIONS',
},
})
}
}
addEventListener('fetch', event => {
const request = event.request
const url = new URL(request.url)
if (url.pathname.startsWith(proxyEndpoint)) {
if (request.method === 'OPTIONS') {
// Handle CORS preflight requests
event.respondWith(handleOptions(request))
} else if (
request.method === 'GET' ||
request.method === 'HEAD' ||
request.method === 'POST'
) {
// Handle requests to the API server
event.respondWith(handleRequest(request))
} else {
event.respondWith(async () => {
return new Response(null, {
status: 405,
statusText: 'Method Not Allowed',
})
})
}
} else {
// Serve demo page
event.respondWith(rawHtmlResponse(demoPage))
}
})
// We support the GET, POST, HEAD, and OPTIONS methods from any origin,
// and accept the Content-Type header on requests. These headers must be
// present on all responses to all CORS requests. In practice, this means
// all responses to OPTIONS requests.
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, HEAD, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
}
// The URL for the remote third party API you want to fetch from
// but does not implement CORS
const apiurl = 'https://workers-tooling.cf/demos/demoapi'
// The endpoint you want the CORS reverse proxy to be on
const proxyEndpoint = '/corsproxy/'
// The rest of this snippet for the demo page
async function rawHtmlResponse(html) {
return new Response(html, {
headers: {
'content-type': 'text/html;charset=UTF-8',
},
})
}
const demoPage = `
<!DOCTYPE html>
<html>
<body>
<h1>API GET without CORS Proxy</h1>
<a target='_blank' href='https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful'>Shows TypeError: Failed to fetch since CORS is misconfigured</a>
<p id='noproxy-status'/>
<code id='noproxy'>Waiting</code>
<h1>API GET with CORS Proxy</h1>
<p id='proxy-status'/>
<code id='proxy'>Waiting</code>
<h1>API POST with CORS Proxy + Preflight</h1>
<p id='proxypreflight-status'/>
<code id='proxypreflight'>Waiting</code>
<script>
let reqs = {};
reqs.noproxy = async () => {
let response = await fetch('${apiurl}')
return await response.json()
}
reqs.proxy = async () => {
let response = await fetch(window.location.origin + '${proxyEndpoint}?apiurl=${apiurl}')
return await response.json()
}
reqs.proxypreflight = async () => {
const reqBody = {
msg: "Hello world!"
}
let response = await fetch(window.location.origin + '${proxyEndpoint}?apiurl=${apiurl}', {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(reqBody),
})
return await response.json()
}
(async () => {
for (const [reqName, req] of Object.entries(reqs)) {
try {
let data = await req()
document.getElementById(reqName).innerHTML = JSON.stringify(data)
} catch (e) {
document.getElementById(reqName).innerHTML = e
}
}
})()
</script>
</body>
</html>`
Redirect a response based on the country code of the visitor
async function handleRequest(request) {
return redirect(request, 'subdomain')
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
/**
* Returns a redirect determined by the country code
* @param {Request} request
*/
function redirect(request) {
The `cf-ipcountry` header is not supported in the previewer
const country = request.headers.get('cf-ipcountry')
const url = countryMap[country]
return Response.redirect(url)
}
/**
* A map of the url's to redirect to
* @param {Object} countryMap
*/
const countryMap = {
"US" : "https://example.com/us",
"EU": "https://eu.example.com/"
}
Send debug information in an errored response and to a logging service.
const LOG_URL = 'https://log-service.example.com/' // Service setup up to receive logs
async function handleRequest(event) {
let response
try {
response = await fetch(event.request)
if (!response.ok) {
let body = await response.text()
throw new Error(
'Bad response at origin. Status: ' +
response.status +
' Body: ' +
body.trim().substring(0, 10), //ensures is string that can be a header
)
}
} catch (err) {
// Without event.waitUntil(), our fetch() to our logging service may
// or may not complete.
event.waitUntil(postLog(err))
const stack = JSON.stringify(err.stack) || err
// Copy the response and initialize body to the stack trace
response = new Response(stack, response)
// Shove our rewritten URL into a header to find out what it was.
response.headers.set('X-Debug-stack', stack)
response.headers.set('X-Debug-err', err)
}
return response
}
addEventListener('fetch', event => {
//Have any uncaught errors thrown go directly to origin
event.passThroughOnException()
event.respondWith(handleRequest(event))
})
function postLog(data) {
return fetch(LOG_URL, {
method: 'POST',
body: data,
})
}
Sends a request to a remote server, reads HTML from the response, then serves that HTML.
async function handleRequest(request) {
const init = {
headers: {
'content-type': 'text/html;charset=UTF-8',
},
}
const response = await fetch(url, init)
const results = await gatherResponse(response)
return new Response(results, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
/**
* gatherResponse awaits and returns a response body as a string.
* Use await gatherResponse(..) in an async function to get the response body
* @param {Response} response
*/
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}
/**
* Example someHost at url is set up to respond with HTML
* Replace url with the host you wish to send requests to
* */
const someHost = 'https://workers-tooling.cf/demos'
const url = someHost + '/static/html'
Sends a GET request and reads in JSON from the response.
async function handleRequest(request) {
const init = {
headers: {
'content-type': type,
},
}
const responses = await Promise.all([fetch(url1, init), fetch(url2, init)])
const results = await Promise.all([gatherResponse(responses[0]), gatherResponse(responses[1])])
return new Response(results, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
/**
* gatherResponse awaits and returns a response body as a string.
* Use await gatherResponse(..) in an async function to get the response body
* @param {Response} response
*/
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}
/**
* Example someHost is set up to return JSON responses
* Replace url1 and url2 with the hosts you wish to
* send requests to
* @param {string} url the URL to send the request to
*/
const someHost = 'https://workers-tooling.cf/demos'
const url1 = someHost + '/requests/json'
const url2 = someHost + '/requests/json'
const type = 'application/json;charset=UTF-8'
Push static assests to a client’s browser without waiting for HTML to render
async function handleRequest(request) {
// If request is for test.css just serve the raw CSS
if (/test.css$/.test(request.url)) {
return new Response(CSS, {
headers: {
'content-type': 'text/css',
},
})
} else {
// serve raw HTML using HTTP/2 for the CSS file
return new Response(HTML, {
headers: {
'content-type': 'text/html',
Link: '</http2_push/h2p/test.css>; rel=preload;',
},
})
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
const CSS = `body { color: red; }`
const HTML = `
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Server push test</title>
<link rel="stylesheet" href="http2_push/h2p/test.css">
</head>
<body>
<h1>Server push test page</h1>
</body>
</html>
`
Recommended practice for forming a request based off the incoming request. First, takes in the incoming request then modifies specific properties like POST body
, redirect
, and the Cloudflare specific property cf
and runs the fetch.
async function handleRequest(request) {
/**
* Best practice is to only assign new properties on the request
* object (i.e. RequestInit props) through either a method or the constructor
*/
let newRequestInit = {
// Change method
method: 'POST',
// Change body
body: JSON.stringify({ bar: 'foo' }),
// Change the redirect mode.
redirect: 'follow',
//Change headers, note this method will erase existing headers
headers: {
'Content-Type': 'application/json',
},
// Change a Cloudflare feature on the outbound response
cf: { apps: false },
}
// Change URL
let url = someUrl
// Change just the host
url = new URL(url)
url.hostname = someHost
// Best practice is to always use the original request to construct the new request
// thereby cloning all the attributes, applying the URL also requires a constructor
// since once a Request has been constructed, its URL is immutable.
const newRequest = new Request(url, new Request(request, newRequestInit))
// Set headers using method
newRequest.headers.set('X-Example', 'bar')
newRequest.headers.set('Content-Type', 'application/json')
try {
return await fetch(newRequest)
} catch (e) {
return new Response(JSON.stringify({ error: e.message }), { status: 500 })
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
/**
* Example someHost is set up to return raw JSON
* @param {string} someUrl the URL to send the request to, since we are setting hostname too only path is applied
* @param {string} someHost the host the request will resolve too
*/
const someHost = 'example.com'
const someUrl = 'https://foo.example.com/api.js'
Recommended practice for mutating a fetched response. First, fetches a request then modifies specific properties which are immutable: status
, statusText
, headers
and body
.
async function handleRequest(request) {
/**
* Best practice is to only assign properties on the response
* object (i.e. ResponseInit props) through either a method or the constructor
* since properties are immutable
*/
let originalResponse = await fetch(request)
let originalBody = await originalResponse.json()
// Change status and statusText
// Make sure to pass in originalResponse to preserving all parts
// of the original response except the part we want to update.
let response = new Response(originalResponse, { status: 500, statusText: 'some message' })
// Change response body by adding the foo prop
let body = JSON.stringify({ foo: 'bar', ...originalBody })
response = new Response(body, response)
// Add a header using set method
response.headers.set('foo', 'bar')
// Set destination header to the value of the source header
if (response.headers.has(headerNameSrc)) {
response.headers.set(headerNameDst, response.headers.get(headerNameSrc))
console.log(
`Response header "${headerNameDst}" was set to "${response.headers.get(headerNameDst)}"`,
)
}
return response
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
/**
* @param {string} headerNameSrc the header to get the new value from
* @param {string} headerNameDst the header to set based off of value in src
*/
const headerNameSrc = 'foo'//'Orig-Header'
const headerNameDst = 'Last-Modified'
Serves an HTML form, then reads POSTs from that form data. Can also be used to read JSON or other POST data from an incoming request.
async function handlePostRequest(request) {
let reqBody = await readRequestBody(request)
let retBody = `The request body sent in was ${reqBody}`
return new Response(retBody)
}
async function handleRequest(request) {
let retBody = `The request was a GET `
return new Response(retBody)
}
addEventListener('fetch', event => {
const { request } = event
const { url } = request
if (url.includes('form')) {
return event.respondWith(rawHtmlResponse(someForm))
}
if (request.method === 'POST') {
return event.respondWith(handlePostRequest(request))
} else if (request.method === 'GET') {
return event.respondWith(handleRequest(request))
}
})
/**
* rawHtmlResponse delievers a response with HTML inputted directly
* into the worker script
* @param {string} html
*/
async function rawHtmlResponse(html) {
const init = {
headers: {
'content-type': 'text/html;charset=UTF-8',
},
}
return new Response(html, init)
}
/**
* readRequestBody reads in the incoming request body
* Use await readRequestBody(..) in an async function to get the string
* @param {Request} request the incoming request to read from
*/
async function readRequestBody(request) {
const { headers } = request
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
const body = await request.json()
return JSON.stringify(body)
} else if (contentType.includes('application/text')) {
const body = await request.text()
return body
} else if (contentType.includes('text/html')) {
const body = await request.text()
return body
} else if (contentType.includes('form')) {
const formData = await request.formData()
let body = {}
for (let entry of formData.entries()) {
body[entry[0]] = entry[1]
}
return JSON.stringify(body)
} else {
let myBlob = await request.blob()
var objectURL = URL.createObjectURL(myBlob)
return objectURL
}
}
const someForm = `
<!DOCTYPE html>
<html>
<body>
<h1>Hello World</h1>
<p>This is all generated using a Worker</p>
<form action="/demos/requests" method="post">
<div>
<label for="say">What do you want to say?</label>
<input name="say" id="say" value="Hi">
</div>
<div>
<label for="to">To who?</label>
<input name="to" id="to" value="Mom">
</div>
<div>
<button>Send my greetings</button>
</div>
</form>
</body>
</html>
Sends a POST request with JSON data from the Workers script.
async function handleRequest(request) {
const init = {
body: JSON.stringify(body),
method: 'POST',
headers: {
'content-type': 'application/json;charset=UTF-8',
},
}
const response = await fetch(url, init)
const results = await gatherResponse(response)
return new Response(results, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
/**
* gatherResponse awaits and returns a response body as a string.
* Use await gatherResponse(..) in an async function to get the response body
* @param {Response} response
*/
async function gatherResponse(response) {
const { headers } = response
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
return await response.json()
} else if (contentType.includes('application/text')) {
return await response.text()
} else if (contentType.includes('text/html')) {
return await response.text()
} else {
return await response.text()
}
}
/**
* Example someHost is set up to take in a JSON request
* Replace url with the host you wish to send requests to
* @param {string} url the URL to send the request to
* @param {BodyInit} body the JSON data to send in the request
*/
const someHost = 'https://workers-tooling.cf/demos'
const url = someHost + '/requests/json'
const body = {
results: ['default data to send'],
errors: null,
msg: 'I sent this to the fetch',
}
Redirect a request by sending a 301 or 302 HTTP response
async function handleRequest(request) {
return Response.redirect(someURLToRedirectTo, code)
}
addEventListener('fetch', async event => {
event.respondWith(handleRequest(event.request))
})
/**
* Example Input
* @param {Request} url where to redirect the response
* @param {number?=301|302} type permanent or temporary redirect
*/
const someURLToRedirectTo = 'https://www.google.com'
const code = 301
Delivers an HTML page from HTML directly in the Worker script.
async function handleRequest(request) {
const init = {
headers: {
'content-type': 'text/html;charset=UTF-8',
},
}
return new Response(someHTML, init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
const someHTML = `<!DOCTYPE html>
<html>
<body>
<h1>Hello World</h1>
<p>This is all generated using a Worker</p>
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</body>
</html>
`
Renders a response of type application/json
to the client
async function handleRequest(request) {
const init = {
headers: {
'content-type': 'application/json;charset=UTF-8',
},
}
return new Response(JSON.stringify(someJSON), init)
}
addEventListener('fetch', event => {
return event.respondWith(handleRequest(event.request))
})
const someJSON = {
result: ['some', 'results'],
errors: null,
msg: 'this is some random json',
}
Inspects the incoming request’s TLS version and blocks if under TLSv1.2.
async function handleRequest(request) {
try {
let tlsVersion = request.cf.tlsVersion
// Allow only TLS versions 1.2 and 1.3
if (tlsVersion != 'TLSv1.2' && tlsVersion != 'TLSv1.3') {
return new Response('Please use TLS version 1.2 or higher.', {
status: 403,
})
}
return fetch(request)
} catch (err) {
console.error(
'request.cf does not exist in the previewer, only in production',
)
return new Response('Error in workers script' + err.message, {
status: 500,
})
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
🔥Lightning-fast, globally distributed Apollo GraphQL server, deployed at the edge using Cloudflare Workers.
wrangler generate my-app
https://github.com/signalnerve/workers-graphql-server
Serve private AWS bucket files from a Worker script
wrangler generate my-app
https://github.com/conzorkingkong/cloud-storage
Image Resizer in C compiled to Wasm with Emscripten
wrangler generate my-app
https://github.com/cloudflare/worker-emscripten-template
Retrieve the dominant color of a PNG or JPEG image
wrangler generate my-app
https://github.com/xtuc/img-color-worker
Log exceptions and errors in your Workers application to Sentry.io - an error tracking tool
wrangler generate my-app
https://github.com/bustle/cf-sentry
Measure download / upload connection speed from the client side, using the Performance Timing API
wrangler generate my-app
https://github.com/cloudflare/worker-speedtest-template
Serve BinAST via a Cloudflare Worker
wrangler generate my-app
https://github.com/xtuc/binast-cf-worker-template
wrangler generate https://github.com/
.
For archived recipes, see the old docs.