Site 302 Redirect Trailing Slash
Introduction
NuxtContent allows me to generate a content centered blog post or article by writing in Markdown. I can author with simple text editor without fussing with HTML codes, css, etc. It even handles things like custom SEO and Social Sharing metadata with front-matter variables at the top of the Markdown file. It encapsulates the key programmer principles of simplicity, flexibility, readability, and self-containment. Indeed this blog post was written this way. Further, with the use the Nuxt npm run generate
command I can turn my fully client functional Vue.js/Nuxt.js web application into a static website that I can deploy to very cheap storage hosting solution such as Amazon S3.
Markdown to HTML
When I write an article and then generate a static site with it, underneath the covers it converts the Markdown text and the supporting NuxtContent Vue framework into a directory and 2 files named index.html
and _payload.json
For example, if I write a markdown article into a file named example.md
, what gets generated for the static site is
example/
example/index.html
example/_payload.json
Dir or Object
The conversion of the page into a directory with two files is a very clever solution and has many benefits but it does introduce the trailing slash issue. Typically a directory or subfolder is represented in a URL with a trailing slash /
, i.e. pennockprojects.com/example/
and an object/file is represented without a trailing slash, i.e. pennockprojects.com/example
. By default, when a browser sees a trailing slash on a URL it will look for an index.html
file in that directory, i.e. it will look for pennocksprojects.com/example/index.html
and when it doesn't see a trailing slash, it will attempt to retrieve the file object directly, i.e. pennockprojects.com/example
.
Trailing Slash Issue
When our Nuxt App is hosted with its own Nuxt Server, it can server side render the object requested for the page route. When the route /example
is called, the server can pull in whatever resources it needs and generate a single object in response. When our Nuxt app is a statically generated, the route becomes a directory /example/
with an index.html
file within it.
AWS S3 302 redirect
When you deploy your statically generated Nuxt site to AWS S3 Website cloud solution, the AWS S3 web server default behavior responds to any request for an object that is actually a directory with a status code of 302, which means "Found but temporarily moved to a new location", and points to the directory version of the object (with the trailing slash). For example, a GET at pennockprojects.com/photos
will return a 302 status code with pennockprojects.com/photos/
redirect.
A Small Diff Has Consequences
This response code does not matter for typical web browsing and your users can blissfully type pennocksprojects.com/photos
and their browser URL doesn't have a trailing slash and everything works. (The browser does all the work to get file underneath the covers.) Where I found out this breaks down is when your site URL is shared on social media, in particular on X/Twitter. I was finding that if you typed a URL without a trailing slash (or copy and pasted from the site URL in the browser) the social share large card image would sometimes not show up like it should. Although this resolved over time, it was still annoying.
X/Twitter Validator Difference
At the twitter card validator tool you can see the difference
Potential Solutions
One potential solution is to use a Lambda function for CloudFront Edge requests. See this blog for details, which I followed to correct this issue for my website.