|
1 | 1 | import FailBot from '../lib/failbot.js'
|
2 | 2 | import { nextApp } from './next.js'
|
| 3 | +import { setFastlySurrogateKey, SURROGATE_ENUMS } from './set-fastly-surrogate-key.js' |
| 4 | +import { cacheControlFactory } from './cache-control.js' |
| 5 | + |
| 6 | +const cacheControl = cacheControlFactory(60) // 1 minute |
3 | 7 |
|
4 | 8 | function shouldLogException(error) {
|
5 | 9 | const IGNORED_ERRORS = [
|
@@ -32,10 +36,34 @@ export default async function handleError(error, req, res, next) {
|
32 | 36 | // anywhere. So this is why we log it additionally.
|
33 | 37 | // Note, not using console.error() because it's arguably handled.
|
34 | 38 | // Some tests might actually expect a 500 error.
|
35 |
| - if ( |
36 |
| - process.env.NODE_ENV === 'test' && |
37 |
| - !(req.path.startsWith('/assets') || req.path.startsWith('/_next/static')) |
38 |
| - ) { |
| 39 | + |
| 40 | + if (req.path.startsWith('/assets') || req.path.startsWith('/_next/static')) { |
| 41 | + // By default, Fastly will cache 404 responses unless otherwise |
| 42 | + // told not to. |
| 43 | + // See https://docs.fastly.com/en/guides/how-caching-and-cdns-work#http-status-codes-cached-by-default |
| 44 | + // Most of the time, that's a good thing! Especially, if bombarded |
| 45 | + // for some static asset that we don't have. |
| 46 | + // E.g. `ab -n 10000 https://docs.github.com/assets/doesnotexist.png` |
| 47 | + // But due to potential timing issue related to how the servers start, |
| 48 | + // what might happen is that a new insteance comes up that |
| 49 | + // contains `<script src="/_next/static/foo.1234.css">` in the HTML. |
| 50 | + // The browser then proceeds to request /_next/static/foo.1234.css |
| 51 | + // but this time it could be unluckily routed to a different instance |
| 52 | + // that hasn't yet been upgraded, so they get a 404. And the CDN will |
| 53 | + // notice this and cache it. |
| 54 | + // Setting a tiny cache gets us a good compromise. It protects us |
| 55 | + // against most stamping herds on 404s (thank you CDN!) but it also |
| 56 | + // clears itself if you get that unlucky timing issue with rolling |
| 57 | + // instances in a new deployment. |
| 58 | + // For more background see issue 1553. |
| 59 | + cacheControl(res) |
| 60 | + // Undo the cookie setting that CSRF sets. |
| 61 | + res.removeHeader('set-cookie') |
| 62 | + // Makes sure the surrogate key is NOT the manual one if it failed. |
| 63 | + // This basically unsets what was assumed in the beginning of |
| 64 | + // loading all the middlewares. |
| 65 | + setFastlySurrogateKey(res, SURROGATE_ENUMS.DEFAULT) |
| 66 | + } else if (process.env.NODE_ENV === 'test') { |
39 | 67 | console.warn('An error occurrred in some middleware handler', error)
|
40 | 68 | }
|
41 | 69 |
|
|
0 commit comments