Reputation: 155
I'm a newbie in Cloudflare Workers.
How to set CORS in Cloudflare Workers?
response = await cache.match(cacheKey);
if (!response) {
// handle fetch data and cache
}
const myHeaders = new Headers();
myHeaders.set("Access-Control-Allow-Origin", event.request.headers.get("Origin"));
return new Response(JSON.stringify({
response
}), {
status: 200, headers: myHeaders
});
Upvotes: 13
Views: 31075
Reputation: 101
add this,
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, HEAD, OPTIONS',
'Access-Control-Max-Age': '86400',
'Access-Control-Allow-Headers' : 'x-worker-key,Content-Type,x-custom-metadata,Content-MD5,x-amz-meta-fileid,x-amz-meta-account_id,x-amz-meta-clientid,x-amz-meta-file_id,x-amz-meta-opportunity_id,x-amz-meta-client_id,x-amz-meta-webhook',
'Access-Control-Allow-Credentials' : 'true',
'Allow': 'GET, POST, PUT, DELETE, HEAD, OPTIONS'
};
export function addCORSHeaders(response: Response){
const newResponse = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers: corsHeaders,
});
return newResponse;
};
consume like this
export function consumer(env: Env,request: Request,response: Response){
//TODO: Code Here
return addCORSHeaders(new Response(response.body)) ;
}
Upvotes: 1
Reputation: 10522
This is the top Google result for 'cloudflare worker cors error'.
Here is a super simple way to set the correct headers.
You can call the Cloudflare function like this:
async function callCloudflareWorker(parameter) {
const workerUrl = `https://name.account.workers.dev/`; // Replace with your actual worker URL
const response = await fetch(workerUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ parameter }),
});
if (!response.ok) {
throw new Error(`Error calling Cloudflare Worker: ${response.statusText}`);
}
const data = await response.json();
return data;
}
This sends the server a request. Because it is coming from the browser, the server needs to send a thumbs up that, yes this is allowed.
Your Cloudflare worker would look like this:
addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
const corsHeaders = {
'Access-Control-Allow-Headers': '*', // What headers are allowed. * is wildcard. Instead of using '*', you can specify a list of specific headers that are allowed, such as: Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept, Authorization.
'Access-Control-Allow-Methods': 'POST', // Allowed methods. Others could be GET, PUT, DELETE etc.
'Access-Control-Allow-Origin': '*', // This is URLs that are allowed to access the server. * is the wildcard character meaning any URL can.
}
async function handleRequest(request) {
if (request.method === "OPTIONS") {
return new Response("OK", {
headers: corsHeaders
});
} else if (request.method === 'POST') {
return doTheWork(request);
} else if (request.method === 'GET') {
return doTheWork(request);
} else {
return new Response("Method not allowed", {
status: 405,
headers: corsHeaders
});
}
}
async function doTheWork(request) {
// Parse the request body to get the parameters
const requestBody = await request.json();
let parameter = requestBody.parameter;
//do the work here
let results = //What your worker does
return new Response(JSON.stringify(results), {
headers: {
'Content-type': 'application/json',
...corsHeaders //uses the spread operator to include the CORS headers.
}
});
}
Notice how you had to include the headers on the response as well. It is like the browser and server are shaking hands that yes, this interaction is ok.
Of course using the * characters has issues, do some research to make sure you know what you are doing if you are setting and using cookies etc.
But this should help rookies like be able to use Cloudflare workers from the front end.
Upvotes: 11
Reputation: 527
Anurag's answer got me 90% of the way there, thank you for that. I'm using itty-router
as well, here's what I had to add.
I created a simple preflight middleware:
const corsHeaders = {
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Origin': '*',
};
export const withCorsPreflight = (request: Request) => {
if (request.method.toLowerCase() === 'options') {
return new Response('ok', {
headers: corsHeaders,
});
}
};
I then added it to every route.
router.all('*', withCorsPreflight);
router.get('/api/another-route', handler);
Hope this helps!
Upvotes: 4
Reputation: 435
Here's how got it working. I'm using Itty Router but this should work the same for a normal worker as well.
router.get("/data", async (request) => {
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
"Access-Control-Allow-Headers": "*",
};
if (request.method.toLowerCase() === "options") {
return new Response("ok", {
headers: corsHeaders,
});
}
try {
const data = await getData();
return new Response(data, {
headers: {
"Content-Type": "application/json",
// don't forget this.👇🏻 You also need to send back the headers with the actual response
...corsHeaders,
},
});
} catch (error) {}
return new Response(JSON.stringify([]), {
headers: corsHeaders,
});
});
Thanks to this Free Egghead video Add CORS Headers to a Third Party API Response in a Workers API
Upvotes: 2
Reputation: 3582
It's quite a pain actually. There is a sample from Cloudflare, but it can't be used directly. I finally worked it out recently, and put the detailed steps into a blog post.
Here is the full code for the worker.
// Reference: https://developers.cloudflare.com/workers/examples/cors-header-proxy
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400",
}
function handleOptions (request) {
// Make sure the necessary headers are present
// for this to be a valid pre-flight request
let headers = request.headers
if (
headers.get("Origin") !== null &&
headers.get("Access-Control-Request-Method") !== null &&
headers.get("Access-Control-Request-Headers") !== null
) {
// Handle CORS pre-flight request.
// If you want to check or reject the requested method + headers
// you can do that here.
let respHeaders = {
...corsHeaders,
// Allow all future content Request headers to go back to browser
// such as Authorization (Bearer) or X-Client-Name-Version
"Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers"),
}
return new Response(null, {
headers: respHeaders,
})
}
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",
},
})
}
}
async function handleRequest (request) {
let response
if (request.method === "OPTIONS") {
response = handleOptions(request)
}
else {
response = await fetch(request)
response = new Response(response.body, response)
response.headers.set("Access-Control-Allow-Origin", "*")
response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
}
return response
}
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});
Upvotes: 22
Reputation: 1566
Your code does not set the Content-Type header. You should either set it with myHeaders.set() or use the original response headers instead of creating an empty headers object:
response = await cache.match(cacheKey);
if (!response) {
// handle fetch data and cache
}
const myHeaders = new Headers(response.headers);
myHeaders.set("Access-Control-Allow-Origin", event.request.headers.get("Origin"));
I'm also questioning why you are trying to use JSON.stringify on the response. I think what you want is something like this:
return new Response(response.body, {status: 200, headers: myHeaders});
Upvotes: 2