mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Fix handling http methods (#748)
* support HEAD method * respond with 501 if method is not GET or HEAD
This commit is contained in:
parent
1dc52dbc6c
commit
e3e0a68b9a
|
@ -1,7 +1,7 @@
|
||||||
import { resolve, join } from 'path'
|
import { resolve, join } from 'path'
|
||||||
import { parse } from 'url'
|
import { parse } from 'url'
|
||||||
import fs from 'mz/fs'
|
import fs from 'mz/fs'
|
||||||
import http from 'http'
|
import http, { STATUS_CODES } from 'http'
|
||||||
import {
|
import {
|
||||||
renderToHTML,
|
renderToHTML,
|
||||||
renderErrorToHTML,
|
renderErrorToHTML,
|
||||||
|
@ -38,7 +38,7 @@ export default class Server {
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (!this.quiet) console.error(err)
|
if (!this.quiet) console.error(err)
|
||||||
res.statusCode = 500
|
res.statusCode = 500
|
||||||
res.end('error')
|
res.end(STATUS_CODES[500])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,43 +67,52 @@ export default class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
defineRoutes () {
|
defineRoutes () {
|
||||||
this.router.get('/_next-prefetcher.js', async (req, res, params) => {
|
const routes = {
|
||||||
const p = join(__dirname, '../client/next-prefetcher-bundle.js')
|
'/_next-prefetcher.js': async (req, res, params) => {
|
||||||
await serveStatic(req, res, p)
|
const p = join(__dirname, '../client/next-prefetcher-bundle.js')
|
||||||
})
|
await this.serveStatic(req, res, p)
|
||||||
|
},
|
||||||
|
|
||||||
this.router.get('/_next/:buildId/main.js', async (req, res, params) => {
|
'/_next/:buildId/main.js': async (req, res, params) => {
|
||||||
this.handleBuildId(params.buildId, res)
|
this.handleBuildId(params.buildId, res)
|
||||||
const p = join(this.dir, '.next/main.js')
|
const p = join(this.dir, '.next/main.js')
|
||||||
await serveStaticWithGzip(req, res, p)
|
await this.serveStaticWithGzip(req, res, p)
|
||||||
})
|
},
|
||||||
|
|
||||||
this.router.get('/_next/:buildId/commons.js', async (req, res, params) => {
|
'/_next/:buildId/commons.js': async (req, res, params) => {
|
||||||
this.handleBuildId(params.buildId, res)
|
this.handleBuildId(params.buildId, res)
|
||||||
const p = join(this.dir, '.next/commons.js')
|
const p = join(this.dir, '.next/commons.js')
|
||||||
await serveStaticWithGzip(req, res, p)
|
await this.serveStaticWithGzip(req, res, p)
|
||||||
})
|
},
|
||||||
|
|
||||||
this.router.get('/_next/:buildId/pages/:path*', async (req, res, params) => {
|
'/_next/:buildId/pages/:path*': async (req, res, params) => {
|
||||||
this.handleBuildId(params.buildId, res)
|
this.handleBuildId(params.buildId, res)
|
||||||
const paths = params.path || ['index']
|
const paths = params.path || ['index']
|
||||||
const pathname = `/${paths.join('/')}`
|
const pathname = `/${paths.join('/')}`
|
||||||
await this.renderJSON(req, res, pathname)
|
await this.renderJSON(req, res, pathname)
|
||||||
})
|
},
|
||||||
|
|
||||||
this.router.get('/_next/:path+', async (req, res, params) => {
|
'/_next/:path+': async (req, res, params) => {
|
||||||
const p = join(__dirname, '..', 'client', ...(params.path || []))
|
const p = join(__dirname, '..', 'client', ...(params.path || []))
|
||||||
await serveStatic(req, res, p)
|
await this.serveStatic(req, res, p)
|
||||||
})
|
},
|
||||||
this.router.get('/static/:path+', async (req, res, params) => {
|
|
||||||
const p = join(this.dir, 'static', ...(params.path || []))
|
|
||||||
await serveStatic(req, res, p)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.router.get('/:path*', async (req, res) => {
|
'/static/:path+': async (req, res, params) => {
|
||||||
const { pathname, query } = parse(req.url, true)
|
const p = join(this.dir, 'static', ...(params.path || []))
|
||||||
await this.render(req, res, pathname, query)
|
await this.serveStatic(req, res, p)
|
||||||
})
|
},
|
||||||
|
|
||||||
|
'/:path*': async (req, res) => {
|
||||||
|
const { pathname, query } = parse(req.url, true)
|
||||||
|
await this.render(req, res, pathname, query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const method of ['GET', 'HEAD']) {
|
||||||
|
for (const p of Object.keys(routes)) {
|
||||||
|
this.router.add(method, p, routes[p])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async start (port) {
|
async start (port) {
|
||||||
|
@ -125,8 +134,14 @@ export default class Server {
|
||||||
const fn = this.router.match(req, res)
|
const fn = this.router.match(req, res)
|
||||||
if (fn) {
|
if (fn) {
|
||||||
await fn()
|
await fn()
|
||||||
} else {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method === 'GET' || req.method === 'HEAD') {
|
||||||
await this.render404(req, res)
|
await this.render404(req, res)
|
||||||
|
} else {
|
||||||
|
res.statusCode = 501
|
||||||
|
res.end(STATUS_CODES[501])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +150,7 @@ export default class Server {
|
||||||
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
|
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
|
||||||
}
|
}
|
||||||
const html = await this.renderToHTML(req, res, pathname, query)
|
const html = await this.renderToHTML(req, res, pathname, query)
|
||||||
sendHTML(res, html)
|
sendHTML(res, html, req.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderToHTML (req, res, pathname, query) {
|
async renderToHTML (req, res, pathname, query) {
|
||||||
|
@ -163,7 +178,7 @@ export default class Server {
|
||||||
|
|
||||||
async renderError (err, req, res, pathname, query) {
|
async renderError (err, req, res, pathname, query) {
|
||||||
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
|
||||||
sendHTML(res, html)
|
sendHTML(res, html, req.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderErrorToHTML (err, req, res, pathname, query) {
|
async renderErrorToHTML (err, req, res, pathname, query) {
|
||||||
|
@ -191,7 +206,7 @@ export default class Server {
|
||||||
async render404 (req, res) {
|
async render404 (req, res) {
|
||||||
const { pathname, query } = parse(req.url, true)
|
const { pathname, query } = parse(req.url, true)
|
||||||
res.statusCode = 404
|
res.statusCode = 404
|
||||||
this.renderErrorToHTML(null, req, res, pathname, query)
|
this.renderError(null, req, res, pathname, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderJSON (req, res, page) {
|
async renderJSON (req, res, page) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import App from '../lib/app'
|
||||||
|
|
||||||
export async function render (req, res, pathname, query, opts) {
|
export async function render (req, res, pathname, query, opts) {
|
||||||
const html = await renderToHTML(req, res, pathname, opts)
|
const html = await renderToHTML(req, res, pathname, opts)
|
||||||
sendHTML(res, html)
|
sendHTML(res, html, req.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderToHTML (req, res, pathname, query, opts) {
|
export function renderToHTML (req, res, pathname, query, opts) {
|
||||||
|
@ -23,7 +23,7 @@ export function renderToHTML (req, res, pathname, query, opts) {
|
||||||
|
|
||||||
export async function renderError (err, req, res, pathname, query, opts) {
|
export async function renderError (err, req, res, pathname, query, opts) {
|
||||||
const html = await renderErrorToHTML(err, req, res, query, opts)
|
const html = await renderErrorToHTML(err, req, res, query, opts)
|
||||||
sendHTML(res, html)
|
sendHTML(res, html, req.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
|
export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
|
||||||
|
@ -111,24 +111,24 @@ export async function renderErrorJSON (err, req, res, { dir = process.cwd(), dev
|
||||||
sendJSON(res, {
|
sendJSON(res, {
|
||||||
component,
|
component,
|
||||||
err: err && dev ? errorToJSON(err) : null
|
err: err && dev ? errorToJSON(err) : null
|
||||||
})
|
}, req.method)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendHTML (res, html) {
|
export function sendHTML (res, html, method) {
|
||||||
if (res.finished) return
|
if (res.finished) return
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'text/html')
|
res.setHeader('Content-Type', 'text/html')
|
||||||
res.setHeader('Content-Length', Buffer.byteLength(html))
|
res.setHeader('Content-Length', Buffer.byteLength(html))
|
||||||
res.end(html)
|
res.end(method === 'HEAD' ? null : html)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sendJSON (res, obj) {
|
export function sendJSON (res, obj, method) {
|
||||||
if (res.finished) return
|
if (res.finished) return
|
||||||
|
|
||||||
const json = JSON.stringify(obj)
|
const json = JSON.stringify(obj)
|
||||||
res.setHeader('Content-Type', 'application/json')
|
res.setHeader('Content-Type', 'application/json')
|
||||||
res.setHeader('Content-Length', Buffer.byteLength(json))
|
res.setHeader('Content-Length', Buffer.byteLength(json))
|
||||||
res.end(json)
|
res.end(method === 'HEAD' ? null : json)
|
||||||
}
|
}
|
||||||
|
|
||||||
function errorToJSON (err) {
|
function errorToJSON (err) {
|
||||||
|
|
|
@ -8,10 +8,6 @@ export default class Router {
|
||||||
this.routes = new Map()
|
this.routes = new Map()
|
||||||
}
|
}
|
||||||
|
|
||||||
get (path, fn) {
|
|
||||||
this.add('GET', path, fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
add (method, path, fn) {
|
add (method, path, fn) {
|
||||||
const routes = this.routes.get(method) || new Set()
|
const routes = this.routes.get(method) || new Set()
|
||||||
routes.add({ match: route(path), fn })
|
routes.add({ match: route(path), fn })
|
||||||
|
|
Loading…
Reference in a new issue