mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Implement ETag support for server rendered pages. (#1693)
This commit is contained in:
parent
e0f71d8448
commit
f82e52935d
|
@ -61,8 +61,10 @@
|
|||
"case-sensitive-paths-webpack-plugin": "2.0.0",
|
||||
"cross-spawn": "5.1.0",
|
||||
"del": "2.2.2",
|
||||
"etag": "1.8.0",
|
||||
"fresh": "0.5.0",
|
||||
"friendly-errors-webpack-plugin": "1.5.0",
|
||||
"glob": "^7.1.1",
|
||||
"glob": "7.1.1",
|
||||
"glob-promise": "3.1.0",
|
||||
"htmlescape": "1.1.1",
|
||||
"http-status": "1.0.1",
|
||||
|
|
|
@ -225,7 +225,7 @@ export default class Server {
|
|||
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
|
||||
}
|
||||
const html = await this.renderToHTML(req, res, pathname, query)
|
||||
return sendHTML(res, html, req.method)
|
||||
return sendHTML(req, res, html, req.method)
|
||||
}
|
||||
|
||||
async renderToHTML (req, res, pathname, query) {
|
||||
|
@ -253,7 +253,7 @@ export default class Server {
|
|||
|
||||
async renderError (err, req, res, pathname, query) {
|
||||
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
||||
return sendHTML(res, html, req.method)
|
||||
return sendHTML(req, res, html, req.method)
|
||||
}
|
||||
|
||||
async renderErrorToHTML (err, req, res, pathname, query) {
|
||||
|
|
|
@ -2,6 +2,8 @@ import { join } from 'path'
|
|||
import { createElement } from 'react'
|
||||
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
|
||||
import send from 'send'
|
||||
import generateETag from 'etag'
|
||||
import fresh from 'fresh'
|
||||
import requireModule from './require'
|
||||
import getConfig from './config'
|
||||
import resolvePath from './resolve'
|
||||
|
@ -13,7 +15,7 @@ import ErrorDebug from '../lib/error-debug'
|
|||
|
||||
export async function render (req, res, pathname, query, opts) {
|
||||
const html = await renderToHTML(req, res, pathname, opts)
|
||||
sendHTML(res, html, req.method)
|
||||
sendHTML(req, res, html, req.method)
|
||||
}
|
||||
|
||||
export function renderToHTML (req, res, pathname, query, opts) {
|
||||
|
@ -22,7 +24,7 @@ export function renderToHTML (req, res, pathname, query, opts) {
|
|||
|
||||
export async function renderError (err, req, res, pathname, query, opts) {
|
||||
const html = await renderErrorToHTML(err, req, res, query, opts)
|
||||
sendHTML(res, html, req.method)
|
||||
sendHTML(req, res, html, req.method)
|
||||
}
|
||||
|
||||
export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
|
||||
|
@ -148,9 +150,17 @@ export async function renderScriptError (req, res, page, error, customFields, op
|
|||
`)
|
||||
}
|
||||
|
||||
export function sendHTML (res, html, method) {
|
||||
export function sendHTML (req, res, html, method) {
|
||||
if (res.finished) return
|
||||
const etag = generateETag(html)
|
||||
|
||||
if (fresh(req.headers, { etag })) {
|
||||
res.statusCode = 304
|
||||
res.end()
|
||||
return
|
||||
}
|
||||
|
||||
res.setHeader('ETag', etag)
|
||||
res.setHeader('Content-Type', 'text/html')
|
||||
res.setHeader('Content-Length', Buffer.byteLength(html))
|
||||
res.end(method === 'HEAD' ? null : html)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* global describe, test, expect */
|
||||
import fetch from 'node-fetch'
|
||||
|
||||
export default function (context) {
|
||||
describe('Misc', () => {
|
||||
|
@ -12,5 +13,14 @@ export default function (context) {
|
|||
const html = await context.app.renderToHTML({}, res, '/finish-response', {})
|
||||
expect(html).toBeFalsy()
|
||||
})
|
||||
|
||||
test('allow etag header support', async () => {
|
||||
const url = `http://localhost:${context.appPort}/stateless`
|
||||
const etag = (await fetch(url)).headers.get('ETag')
|
||||
|
||||
const headers = { 'If-None-Match': etag }
|
||||
const res2 = await fetch(url, { headers })
|
||||
expect(res2.status).toBe(304)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { pkg } from 'next-test-utils'
|
|||
export default function ({ app }) {
|
||||
describe('X-Powered-By header', () => {
|
||||
test('set it by default', async () => {
|
||||
const req = { url: '/stateless' }
|
||||
const req = { url: '/stateless', headers: {} }
|
||||
const headers = {}
|
||||
const res = {
|
||||
setHeader (key, value) {
|
||||
|
@ -18,7 +18,7 @@ export default function ({ app }) {
|
|||
})
|
||||
|
||||
test('do not set it when poweredByHeader==false', async () => {
|
||||
const req = { url: '/stateless' }
|
||||
const req = { url: '/stateless', headers: {} }
|
||||
const originalConfigValue = app.config.poweredByHeader
|
||||
app.config.poweredByHeader = false
|
||||
const res = {
|
||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -1972,7 +1972,7 @@ esutils@^2.0.0, esutils@^2.0.2:
|
|||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
|
||||
etag@~1.8.0:
|
||||
etag@1.8.0, etag@~1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
|
||||
|
||||
|
@ -2331,17 +2331,7 @@ glob-promise@3.1.0:
|
|||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/glob-promise/-/glob-promise-3.1.0.tgz#198882a3817be7dc2c55f92623aa9e7b3f82d1eb"
|
||||
|
||||
glob@^6.0.1:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
|
||||
dependencies:
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "2 || 3"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
|
||||
glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
||||
dependencies:
|
||||
|
@ -2352,6 +2342,16 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
|
|||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^6.0.1:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
|
||||
dependencies:
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "2 || 3"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
global@^4.3.0:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.npmjs.org/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
|
||||
|
|
Loading…
Reference in a new issue