1
0
Fork 0
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:
Naoyuki Kanezawa 2017-01-13 00:38:43 +09:00 committed by Guillermo Rauch
parent 1dc52dbc6c
commit e3e0a68b9a
3 changed files with 60 additions and 49 deletions

View file

@ -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) {

View file

@ -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) {

View file

@ -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 })