feat(server): add config option to define etag hash function (#6438)

This commit is contained in:
Pim 2019-09-20 20:49:16 +02:00 committed by Pooya Parsa
parent 75f8564cdc
commit 4e4aa4d5d4
4 changed files with 43 additions and 1 deletions

View File

@ -219,6 +219,21 @@ export function getNuxtConfig (_options) {
options.debug = options.dev options.debug = options.dev
} }
// Validate that etag.hash is a function, if not unset it
if (options.render.etag) {
const { hash } = options.render.etag
if (hash) {
const isFn = typeof hash === 'function'
if (!isFn) {
options.render.etag.hash = undefined
if (options.dev) {
consola.warn(`render.etag.hash should be a function, received ${typeof hash} instead`)
}
}
}
}
// Apply default hash to CSP option // Apply default hash to CSP option
if (options.render.csp) { if (options.render.csp) {
options.render.csp = defaults({}, options.render.csp, { options.render.csp = defaults({}, options.render.csp, {

View File

@ -87,6 +87,16 @@ describe('config: options', () => {
expect(store).toEqual(true) expect(store).toEqual(true)
}) })
test('should unset and warn when etag.hash not a function', () => {
const { render: { etag } } = getNuxtConfig({ render: { etag: { hash: true } } })
expect(etag).toMatchObject({ hash: undefined })
expect(consola.warn).not.toHaveBeenCalledWith('render.etag.hash should be a function, received boolean instead')
const { render: { etag: etagDev } } = getNuxtConfig({ dev: true, render: { etag: { hash: true } } })
expect(etagDev).toMatchObject({ hash: undefined })
expect(consola.warn).toHaveBeenCalledWith('render.etag.hash should be a function, received boolean instead')
})
test('should enable csp', () => { test('should enable csp', () => {
const { render: { csp } } = getNuxtConfig({ render: { csp: { allowedSources: true, test: true } } }) const { render: { csp } } = getNuxtConfig({ render: { csp: { allowedSources: true, test: true } } })
expect(csp).toEqual({ expect(csp).toEqual({

View File

@ -38,7 +38,8 @@ export default ({ options, nuxt, renderRoute, resources }) => async function nux
// Add ETag header // Add ETag header
if (!error && options.render.etag) { if (!error && options.render.etag) {
const etag = generateETag(html, options.render.etag) const { hash } = options.render.etag
const etag = hash ? hash(html, options.render.etag) : generateETag(html, options.render.etag)
if (fresh(req.headers, { etag })) { if (fresh(req.headers, { etag })) {
res.statusCode = 304 res.statusCode = 304
res.end() res.end()

View File

@ -117,6 +117,22 @@ describe('server: nuxtMiddleware', () => {
expect(res.setHeader).nthCalledWith(1, 'ETag', 'etag-hash') expect(res.setHeader).nthCalledWith(1, 'ETag', 'etag-hash')
}) })
test('should set etag after rendering through hook', async () => {
const context = createContext()
const hash = jest.fn(() => 'etag-hook')
context.options.render.etag = { hash }
const result = { html: 'rendered html' }
context.renderRoute.mockReturnValue(result)
const nuxtMiddleware = createNuxtMiddleware(context)
const { req, res, next } = createServerContext()
await nuxtMiddleware(req, res, next)
expect(hash).toBeCalledWith('rendered html', expect.any(Object))
expect(res.setHeader).nthCalledWith(1, 'ETag', 'etag-hook')
})
test('should return 304 if request is fresh', async () => { test('should return 304 if request is fresh', async () => {
const context = createContext() const context = createContext()
const result = { html: 'rendered html' } const result = { html: 'rendered html' }