Skip to content

Commit aca3dc6

Browse files
piehorinokai
andauthored
fix: pass only first language to next-server to match platform redirects support (#2138)
* fix: pass only first language to next-server to match platform redirects support * test: add test case * test: some cleanup in cypress test, extra assertion and some more comments * fix: apply accept-language filtering only in ODB mode * test: add escape hatch to use ~odb handling when not actually using odb --------- Co-authored-by: Rob Stanford <[email protected]>
1 parent d133903 commit aca3dc6

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

cypress/e2e/default/i18n.cy.ts

+30
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,34 @@ describe('Localization', () => {
3535

3636
cy.findByText('The current locale is en')
3737
})
38+
39+
it(`function handler doesn't produce locale when first language in 'Accept-Language' header is not matching any of locales`, () => {
40+
cy.request({
41+
url: `/`,
42+
followRedirect: false,
43+
headers: {
44+
// jp is not in i18n config, fr is in config
45+
// Netlify Redirects only match on first language
46+
// https://docs.netlify.com/routing/redirects/redirect-options/#redirect-by-country-or-language
47+
// > Language-based redirects always match against the first language reported by the browser in the Accept-Language header regardless of quality value weighting.
48+
// while Next.js matches on every language: https://github.com/vercel/next.js/blob/5d9597879c46b383d595d6f7b37fd373325b7544/test/unit/accept-headers.test.ts
49+
'Accept-Language': 'jp, fr;q=0.9',
50+
// make sure we don't use cached results
51+
cookie: '__prerender_bypass=1',
52+
// above cookie header cause us to hit non-ODB function variant
53+
// below header allow us to force ODB-only code path despite not running ODB (this is just for testing purposes)
54+
'x-next-just-first-accept-language': '1',
55+
},
56+
}).then((response) => {
57+
// make sure we didn't hit SSR handler - not ODB and nothing else handles this request
58+
// once platform starts supporting more languages in Accept-Language header - this test
59+
// will start failing because then we will get platform level redirect
60+
expect(response.headers['x-nf-render-mode']).to.eq('ssr')
61+
62+
// we don't expect for function handler to respond with a redirect
63+
// locale redirects should be handled by Netlify redirects
64+
// otherwise we could wrongly cache locale redirect generated by ODB
65+
expect(response.status).to.eq(200)
66+
})
67+
})
3868
})

packages/runtime/src/templates/getHandler.ts

+10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ const makeHandler = ({ conf, app, pageRoot, NextServer, staticManifest = [], mod
130130
const query = new URLSearchParams(event.queryStringParameters).toString()
131131
event.path = query ? `${event.path}?${query}` : event.path
132132

133+
if (event.headers['accept-language'] && (mode === 'odb' || event.headers['x-next-just-first-accept-language'])) {
134+
// keep just first language to match Netlify redirect limitation:
135+
// https://docs.netlify.com/routing/redirects/redirect-options/#redirect-by-country-or-language
136+
// > Language-based redirects always match against the first language reported by the browser in the Accept-Language header regardless of quality value weighting.
137+
// If we wouldn't keep just first language, it's possible for `next-server` to generate locale redirect that could be cached by ODB
138+
// because it matches on every language listed: https://github.com/vercel/next.js/blob/5d9597879c46b383d595d6f7b37fd373325b7544/test/unit/accept-headers.test.ts
139+
// 'x-next-just-first-accept-language' header is escape hatch to be able to hit this code for tests (both automated and manual)
140+
event.headers['accept-language'] = event.headers['accept-language'].replace(/\s*,.*$/, '')
141+
}
142+
133143
const { headers, ...result } = await getBridge(event, context).launcher(event, context)
134144

135145
// Convert all headers to multiValueHeaders

0 commit comments

Comments
 (0)