If you want to get started quickly, click on the button below.
This creates a repository in your GitHub account and deploys the application to Cloudflare Workers.
export default {
async fetch(request) {
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400",
};
// The URL for the remote third party API you want to fetch from
// but does not implement CORS
const API_URL = "https://examples.cloudflareworkers.com/demos/demoapi";
// The endpoint you want the CORS reverse proxy to be on
const PROXY_ENDPOINT = "/corsproxy/";
// The rest of this snippet for the demo page
function rawHtmlResponse(html) {
return new Response(html, {
headers: {
"content-type": "text/html;charset=UTF-8",
},
});
}
const DEMO_PAGE = `
<!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 = () => {
return fetch("${API_URL}").then(r => r.json())
}
reqs.proxy = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
return fetch(window.location.origin + href).then(r => r.json())
}
reqs.proxypreflight = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
let response = await fetch(window.location.origin + href, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
msg: "Hello world!"
})
})
return 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>
`;
async function handleRequest(request) {
const url = new URL(request.url);
let apiUrl = url.searchParams.get("apiurl");
if (apiUrl == null) {
apiUrl = API_URL;
}
// Rewrite request to point to API URL. This also makes the request mutable
// so you can add the correct Origin header to make the API server think
// that this request is not cross-site.
request = new Request(apiUrl, request);
request.headers.set("Origin", new URL(apiUrl).origin);
let response = await fetch(request);
// Recreate the response so you 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;
}
async function handleOptions(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 preflight requests.
return new Response(null, {
headers: {
...corsHeaders,
"Access-Control-Allow-Headers": request.headers.get(
"Access-Control-Request-Headers",
),
},
});
} else {
// Handle standard OPTIONS request.
return new Response(null, {
headers: {
Allow: "GET, HEAD, POST, OPTIONS",
},
});
}
}
const url = new URL(request.url);
if (url.pathname.startsWith(PROXY_ENDPOINT)) {
if (request.method === "OPTIONS") {
// Handle CORS preflight requests
return handleOptions(request);
} else if (
request.method === "GET" ||
request.method === "HEAD" ||
request.method === "POST"
) {
// Handle requests to the API server
return handleRequest(request);
} else {
return new Response(null, {
status: 405,
statusText: "Method Not Allowed",
});
}
} else {
return rawHtmlResponse(DEMO_PAGE);
}
},
};export default {
async fetch(request): Promise<Response> {
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400",
};
// The URL for the remote third party API you want to fetch from
// but does not implement CORS
const API_URL = "https://examples.cloudflareworkers.com/demos/demoapi";
// The endpoint you want the CORS reverse proxy to be on
const PROXY_ENDPOINT = "/corsproxy/";
// The rest of this snippet for the demo page
function rawHtmlResponse(html) {
return new Response(html, {
headers: {
"content-type": "text/html;charset=UTF-8",
},
});
}
const DEMO_PAGE = `
<!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 = () => {
return fetch("${API_URL}").then(r => r.json())
}
reqs.proxy = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
return fetch(window.location.origin + href).then(r => r.json())
}
reqs.proxypreflight = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
let response = await fetch(window.location.origin + href, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
msg: "Hello world!"
})
})
return response.json()
}
(async () => {
for (const [reqName, req] of Object.entries(reqs)) {
try {
let data = await req()
document.getElementById(reqName).textContent = JSON.stringify(data)
} catch (e) {
document.getElementById(reqName).textContent = e
}
}
})()
</script>
</body>
</html>
`;
async function handleRequest(request) {
const url = new URL(request.url);
let apiUrl = url.searchParams.get("apiurl");
if (apiUrl == null) {
apiUrl = API_URL;
}
// Rewrite request to point to API URL. This also makes the request mutable
// so you can add the correct Origin header to make the API server think
// that this request is not cross-site.
request = new Request(apiUrl, request);
request.headers.set("Origin", new URL(apiUrl).origin);
let response = await fetch(request);
// Recreate the response so you 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;
}
async function handleOptions(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 preflight requests.
return new Response(null, {
headers: {
...corsHeaders,
"Access-Control-Allow-Headers": request.headers.get(
"Access-Control-Request-Headers",
),
},
});
} else {
// Handle standard OPTIONS request.
return new Response(null, {
headers: {
Allow: "GET, HEAD, POST, OPTIONS",
},
});
}
}
const url = new URL(request.url);
if (url.pathname.startsWith(PROXY_ENDPOINT)) {
if (request.method === "OPTIONS") {
// Handle CORS preflight requests
return handleOptions(request);
} else if (
request.method === "GET" ||
request.method === "HEAD" ||
request.method === "POST"
) {
// Handle requests to the API server
return handleRequest(request);
} else {
return new Response(null, {
status: 405,
statusText: "Method Not Allowed",
});
}
} else {
return rawHtmlResponse(DEMO_PAGE);
}
},
} satisfies ExportedHandler;import { Hono } from "hono";
import { cors } from "hono/cors";
// The URL for the remote third party API you want to fetch from
// but does not implement CORS
const API_URL = "https://examples.cloudflareworkers.com/demos/demoapi";
// The endpoint you want the CORS reverse proxy to be on
const PROXY_ENDPOINT = "/corsproxy/";
const app = new Hono();
// Demo page handler
app.get("*", async (c) => {
// Only handle non-proxy requests with this handler
if (c.req.path.startsWith(PROXY_ENDPOINT)) {
return next();
}
// Create the demo page HTML
const DEMO_PAGE = `
<!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 = () => {
return fetch("${API_URL}").then(r => r.json())
}
reqs.proxy = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
return fetch(window.location.origin + href).then(r => r.json())
}
reqs.proxypreflight = async () => {
let href = "${PROXY_ENDPOINT}?apiurl=${API_URL}"
let response = await fetch(window.location.origin + href, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
msg: "Hello world!"
})
})
return 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>
`;
return c.html(DEMO_PAGE);
});
// CORS proxy routes
app.on(["GET", "HEAD", "POST", "OPTIONS"], PROXY_ENDPOINT + "*", async (c) => {
const url = new URL(c.req.url);
// Handle OPTIONS preflight requests
if (c.req.method === "OPTIONS") {
const origin = c.req.header("Origin");
const requestMethod = c.req.header("Access-Control-Request-Method");
const requestHeaders = c.req.header("Access-Control-Request-Headers");
if (origin && requestMethod && requestHeaders) {
// Handle CORS preflight requests
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400",
"Access-Control-Allow-Headers": requestHeaders,
},
});
} else {
// Handle standard OPTIONS request
return new Response(null, {
headers: {
Allow: "GET, HEAD, POST, OPTIONS",
},
});
}
}
// Handle actual requests
let apiUrl = url.searchParams.get("apiurl") || API_URL;
// Rewrite request to point to API URL
const modifiedRequest = new Request(apiUrl, c.req.raw);
modifiedRequest.headers.set("Origin", new URL(apiUrl).origin);
let response = await fetch(modifiedRequest);
// 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;
});
// Handle method not allowed for proxy endpoint
app.all(PROXY_ENDPOINT + "*", (c) => {
return new Response(null, {
status: 405,
statusText: "Method Not Allowed",
});
});
export default app;from workers import WorkerEntrypoint, Response, fetch
from js import Request
from urllib.parse import urlparse, parse_qs
class Default(WorkerEntrypoint):
async def fetch(self, request):
cors_headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
"Access-Control-Max-Age": "86400",
}
api_url = "https://examples.cloudflareworkers.com/demos/demoapi"
proxy_endpoint = "/corsproxy/"
def raw_html_response(html):
return Response(html, headers={"content-type": "text/html;charset=UTF-8"})
demo_page = f'''
<!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 = () => {{
return fetch("{api_url}").then(r => r.json())
}}
reqs.proxy = async () => {{
let href = "{proxy_endpoint}?apiurl={api_url}"
return fetch(window.location.origin + href).then(r => r.json())
}}
reqs.proxypreflight = async () => {{
let href = "{proxy_endpoint}?apiurl={api_url}"
let response = await fetch(window.location.origin + href, {{
method: "POST",
headers: {{
"Content-Type": "application/json"
}},
body: JSON.stringify({{
msg: "Hello world!"
}})
}})
return 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>
'''
async def handle_request(request):
parsed = urlparse(request.url)
params = parse_qs(parsed.query)
api_url2 = params.get("apiurl", [None])[0]
if not api_url2:
api_url2 = api_url
target = urlparse(api_url2)
request = Request.new(api_url2, request)
request.headers["Origin"] = f"{target.scheme}://{target.netloc}"
response = await fetch(request)
response = Response(response.body, headers=dict(response.headers))
response.headers["Access-Control-Allow-Origin"] = f"{parsed.scheme}://{parsed.netloc}"
response.headers["Vary"] = "Origin"
return response
async def handle_options(request):
if "Origin" in request.headers and "Access-Control-Request-Method" in request.headers and "Access-Control-Request-Headers" in request.headers:
return Response(None, headers={
**cors_headers,
"Access-Control-Allow-Headers": request.headers["Access-Control-Request-Headers"],
})
return Response(None, headers={"Allow": "GET, HEAD, POST, OPTIONS"})
parsed = urlparse(request.url)
if parsed.path.startswith(proxy_endpoint):
if request.method == "OPTIONS":
return handle_options(request)
if request.method in ("GET", "HEAD", "POST"):
return handle_request(request)
return Response(None, status=405)
return raw_html_response(demo_page)use std::{borrow::Cow, collections::HashMap};
use worker::*;
fn raw_html_response(html: &str) -> Result<Response> {
Response::from_html(html)
}
async fn handle_request(req: Request, api_url: &str) -> Result<Response> {
let url = req.url().unwrap();
let mut api_url2 = url
.query_pairs()
.find(|x| x.0 == Cow::Borrowed("apiurl"))
.unwrap()
.1
.to_string();
if api_url2 == String::from("") {
api_url2 = api_url.to_string();
}
let mut request = req.clone_mut()?;
*request.path_mut()? = api_url2.clone();
if let url::Origin::Tuple(origin, _, _) = Url::parse(&api_url2)?.origin() {
(*request.headers_mut()?).set("Origin", &origin)?;
}
let mut response = Fetch::Request(request).send().await?.cloned()?;
let headers = response.headers_mut();
if let url::Origin::Tuple(origin, _, _) = url.origin() {
headers.set("Access-Control-Allow-Origin", &origin)?;
headers.set("Vary", "Origin")?;
}
Ok(response)
}
fn handle_options(req: Request, cors_headers: &HashMap<&str, &str>) -> Result<Response> {
let headers: Vec<_> = req.headers().keys().collect();
if [
"access-control-request-method",
"access-control-request-headers",
"origin",
]
.iter()
.all(|i| headers.contains(&i.to_string()))
{
let mut headers = Headers::new();
for (k, v) in cors_headers.iter() {
headers.set(k, v)?;
}
return Ok(Response::empty()?.with_headers(headers));
}
Response::empty()
}
#[event(fetch)]
async fn fetch(req: Request, _env: Env, _ctx: Context) -> Result<Response> {
let cors_headers = HashMap::from([
("Access-Control-Allow-Origin", "*"),
("Access-Control-Allow-Methods", "GET,HEAD,POST,OPTIONS"),
("Access-Control-Max-Age", "86400"),
]);
let api_url = "https://examples.cloudflareworkers.com/demos/demoapi";
let proxy_endpoint = "/corsproxy/";
let demo_page = format!(
r#"
<!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 = () => {{
return fetch("{api_url}").then(r => r.json())
}}
reqs.proxy = async () => {{
let href = "{proxy_endpoint}?apiurl={api_url}"
return fetch(window.location.origin + href).then(r => r.json())
}}
reqs.proxypreflight = async () => {{
let href = "{proxy_endpoint}?apiurl={api_url}"
let response = await fetch(window.location.origin + href, {{
method: "POST",
headers: {{
"Content-Type": "application/json"
}},
body: JSON.stringify({{
msg: "Hello world!"
}})
}})
return 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>
"#
);
if req.url()?.path().starts_with(proxy_endpoint) {
match req.method() {
Method::Options => return handle_options(req, &cors_headers),
Method::Get | Method::Head | Method::Post => return handle_request(req, api_url).await,
_ => return Response::error("Method Not Allowed", 405),
}
}
raw_html_response(&demo_page)
}