Skip to content

Instantly share code, notes, and snippets.

@GregBrimble
Last active March 17, 2022 13:37
Show Gist options
  • Save GregBrimble/d7403a5a88d9f95415a62be1baacb3ac to your computer and use it in GitHub Desktop.
Save GregBrimble/d7403a5a88d9f95415a62be1baacb3ac to your computer and use it in GitHub Desktop.
Force trailing slashes

Force Trailing Slashes

This example show how to force trailing slashes using a custom _worker.js file in your Cloudflare Pages project.

Usage

Copy the _worker.js file into your project's build output directory.

Behaviour

For requests to URLS without a trailing slash that would ordinarily serve an HTML asset, we redirect the request to the URL with a trailing slash.

For requests to URLs with a trailing slash, we flatten the default redirect (which would ordinarily strip the trailing slash) and serve the resulting page.

Examples

For the file /foo.html:

For the file /bar/index.html:

For the file /bin:

For the file /index.html:

And finally, for a non-existent file:

export default {
async fetch(request, env) {
let { pathname, origin, search } = new URL(request.url);
if (pathname.endsWith("/")) {
// Serve /foo.html at /foo/
// Serve /bar/index.html at /bar/
return env.ASSETS.fetch(request, { redirect: "follow" });
} else {
const assetPathname = pathname.replace(/\/(index(.html)?)?$/, "");
const assetURL = new URL(`${assetPathname}${search}`, origin);
let assetRequest = new Request(assetURL, request);
assetRequest = new Request(assetRequest, {
headers: {
...Object.fromEntries(request.headers.entries()),
"cf-worker": "deprecated-pages=disable-spa-mode",
},
});
const assetResponse = await env.ASSETS.fetch(assetRequest, {
redirect: "follow",
});
if (
assetResponse.status === 200 &&
assetResponse.headers.get("content-type").includes("text/html")
) {
// If an HTML asset can eventually be served at the URL with a trailing slash, redirect to the URL with a trailing slash.
return new Response(null, {
status: 302,
headers: {
Location: `${assetPathname}/${search}`,
},
});
} else {
// Serve /bin at /bin as normal
// Serve /non-existent with normal 404 behavior (404 /404.html if available or 200 /index.html if not)
return env.ASSETS.fetch(request);
}
}
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment