Add index.js
This commit is contained in:
parent
8bf1693cc0
commit
9228c5ee4e
136
index.js
Normal file
136
index.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* Cloudflare Worker to cache a URL on all US Edge servers
|
||||||
|
*
|
||||||
|
* This worker:
|
||||||
|
* 1. Accepts a target URL via query parameter or POST body
|
||||||
|
* 2. Fetches the URL using Cloudflare's fetch API
|
||||||
|
* 3. Forces caching by setting appropriate cache headers
|
||||||
|
* 4. Can be configured to cache on specific US regions or all of them
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Define US Cloudflare regions (These are the major US colo locations)
|
||||||
|
const US_REGIONS = [
|
||||||
|
"IAD", // Washington DC (Northern Virginia)
|
||||||
|
"EWR", // Newark, NJ
|
||||||
|
"ATL", // Atlanta, GA
|
||||||
|
"MIA", // Miami, FL
|
||||||
|
"ORD", // Chicago, IL
|
||||||
|
"DFW", // Dallas, TX
|
||||||
|
"DEN", // Denver, CO
|
||||||
|
"SEA", // Seattle, WA
|
||||||
|
"LAX", // Los Angeles, CA
|
||||||
|
"SJC", // San Jose, CA
|
||||||
|
"PHX" // Phoenix, AZ
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
async fetch(request, env, ctx) {
|
||||||
|
// Create the response headers with CORS support
|
||||||
|
const headers = new Headers({
|
||||||
|
"Access-Control-Allow-Origin": "*",
|
||||||
|
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
||||||
|
"Access-Control-Allow-Headers": "Content-Type",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle OPTIONS requests (pre-flight for CORS)
|
||||||
|
if (request.method === "OPTIONS") {
|
||||||
|
return new Response(null, { headers });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the target URL from query params or POST body
|
||||||
|
let targetUrl;
|
||||||
|
if (request.method === "POST") {
|
||||||
|
try {
|
||||||
|
const body = await request.json();
|
||||||
|
targetUrl = body.url;
|
||||||
|
} catch (error) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: "Invalid JSON body" }),
|
||||||
|
{ headers, status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const url = new URL(request.url);
|
||||||
|
targetUrl = url.searchParams.get("url");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the target URL
|
||||||
|
if (!targetUrl) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: "Missing 'url' parameter" }),
|
||||||
|
{ headers, status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
new URL(targetUrl); // Validate URL format
|
||||||
|
} catch (error) {
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ error: "Invalid URL format" }),
|
||||||
|
{ headers, status: 400 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all regions in parallel
|
||||||
|
const results = await Promise.allSettled(US_REGIONS.map(async (region) => {
|
||||||
|
return await cacheInRegion(targetUrl, region);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Compile results
|
||||||
|
const response = {
|
||||||
|
url: targetUrl,
|
||||||
|
cached: true,
|
||||||
|
regionResults: results.map((result, index) => ({
|
||||||
|
region: US_REGIONS[index],
|
||||||
|
success: result.status === "fulfilled",
|
||||||
|
status: result.status === "fulfilled" ? result.value.status : null,
|
||||||
|
error: result.status === "rejected" ? result.reason.message : null
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(response, null, 2), { headers });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to cache the URL in a specific Cloudflare region
|
||||||
|
*
|
||||||
|
* @param {string} url - The URL to cache
|
||||||
|
* @param {string} region - The Cloudflare region code
|
||||||
|
* @returns {Promise<Object>} - The fetch response details
|
||||||
|
*/
|
||||||
|
async function cacheInRegion(url, region) {
|
||||||
|
// Create fetch request with cache control headers
|
||||||
|
const cacheRequest = new Request(url, {
|
||||||
|
headers: {
|
||||||
|
// CF-specific header to route to a specific region
|
||||||
|
"CF-Worker-Request-Region": region,
|
||||||
|
// Headers to encourage caching
|
||||||
|
"Cache-Control": "public, max-age=86400",
|
||||||
|
// Tell Cloudflare that we're a cache warmer
|
||||||
|
"User-Agent": "Cloudflare-Cache-Warmer/1.0"
|
||||||
|
},
|
||||||
|
cf: {
|
||||||
|
// Force caching even if origin has no-store
|
||||||
|
cacheEverything: true,
|
||||||
|
// Cache for 1 day
|
||||||
|
cacheTtl: 86400,
|
||||||
|
// Attempt to resolve through the specified region
|
||||||
|
resolveOverride: region
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Perform the fetch
|
||||||
|
const response = await fetch(cacheRequest);
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
cached: response.headers.get("CF-Cache-Status") === "HIT" ||
|
||||||
|
response.headers.get("CF-Cache-Status") === "MISS", // MISS on first cache, but still stored
|
||||||
|
headers: {
|
||||||
|
"CF-Cache-Status": response.headers.get("CF-Cache-Status"),
|
||||||
|
"CF-Ray": response.headers.get("CF-Ray")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user