Next.js: Can't remove x-powered-by header in Next 5

Created on 6 Feb 2018  ·  15Comments  ·  Source: vercel/next.js

  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior


The recent change in Next.js 5.0.0 removed the poweredByHeader options from next.config.js and instructs the user to remove it in their custom server.

Current Behavior



X-Powered-By header cannot be removed or overwritten in custom Express or Koa server.

Steps to Reproduce (for bugs)



Tested using Express & Koa examples.

Express

https://custom-server-express-nobxbpklyw.now.sh

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
.then(() => {
  const server = express()

  server.get('/a', (req, res) => {
    return app.render(req, res, '/b', req.query)
  })

  server.get('/b', (req, res) => {
    return app.render(req, res, '/a', req.query)
  })

  server.get('/posts/:id', (req, res) => {
    return app.render(req, res, '/posts', { id: req.params.id })
  })

  server.get('*', (req, res) => {
    res.removeHeader('x-powered-by')
    return handle(req, res)
  })

  server.listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

Koa

https://custom-server-koa-wxksegmzhf.now.sh

const Koa = require('koa')
const next = require('next')
const Router = require('koa-router')

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
.then(() => {
  const server = new Koa()
  const router = new Router()

  router.get('/a', async ctx => {
    await app.render(ctx.req, ctx.res, '/b', ctx.query)
    ctx.respond = false
  })

  router.get('/b', async ctx => {
    await app.render(ctx.req, ctx.res, '/a', ctx.query)
    ctx.respond = false
  })

  router.get('*', async ctx => {
    await handle(ctx.req, ctx.res)
    ctx.respond = false
  })

  server.use(async (ctx, next) => {
    ctx.res.statusCode = 200
    ctx.response.remove('X-Powered-By')
    await next()
  })

  server.use(router.routes())
  server.listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

Context


Your Environment


| Tech | Version |
|---------|---------|
| next | 5.0.0 |
| node | 8.8.1 |
| OS | macOS 10.13.3 |
| browser | Chrome |

bug

Most helpful comment

How about:

const app = next({ dev, xPoweredBy: false })

and/or

xPoweredBy: false

in next.config.js ?

All 15 comments

in the express example, maybe try

  server.use( (req, res, next) => {
    res.removeHeader('x-powered-by')
    next()
  })

and put it before all the routes(or the routes you don't want to have the header)

Is it normal for x-powered-by to still linger on a hard refresh?

I noticed that when I F5 refresh, the request URL: http://localhost:3000/ has the x-powered-by but when it switches over to: http://localhost:3000/_next/-/page/index.js it gets removed.

I think we had an option for this.
We should bring that again.
(It was removed by mistake I guess)

@ericmai624 tried your snippet and that didn't work (also tried using Helmet and that didn't work either)

This is the commit that pulled it from next.config.js: https://github.com/zeit/next.js/pull/3578/commits/fb7c8624d43be7d639be50eacebfd063e7a16d39

@timteeling we're going to discuss this internally, either the option comes back or we remove it alltogether 🙏

I have been rewriting the render middleware of Next.js to get around this issue (as well as for adding one caching hook):

import { isResSent } from 'next/dist/lib/utils'
import { sendHTML } from 'next/dist/server/render'

// ...

html = await nextApp.renderToHTML(req, res, route.page, query)

if (isResSent(res)) {
  return
}

// "no-cache" indicates that the returned response can't be used to satisfy a subsequent request
// to the same URL without first checking with the server if the response has changed.
// As a result, if a proper validation token (ETag) is present,
// no-cache incurs a roundtrip to validate the cached response,
// but can eliminate the download if the resource has not changed.
res.setHeader('Cache-Control', 'public, no-cache')
// The logic was extracted from https://github.com/zeit/next.js/blob/955cc82736f6e1e3913a8d94d549e40e5cf296d0/server/index.js#L311-L327
sendHTML(req, res, html, req.method, nextApp.renderOpts)

https://github.com/zeit/next.js/blob/955cc82736f6e1e3913a8d94d549e40e5cf296d0/server/index.js#L325

How about:

const app = next({ dev, xPoweredBy: false })

and/or

xPoweredBy: false

in next.config.js ?

I also tried server.set('X-Powered-By', pkg.author.name); without luck. Seems like any Express.js settings are ignored in case of next.js

PR #3791 , however, now that I read this again I see we may have wanted this to take place in next.config.js as well. I think that would be the preferable place (next.config.js) as it would not require a custom server if someone wanted to turn this off and falls in line with. (PR has been updated.)

Would we want to have a "configuration" section for things like this, or instead keep it top-level in this case?

Can make any changes desired if we want to move forward.

Ah @timneutkens , didn't see this was assigned. Sorry about that.
Let me know how you want to proceed, you may already have an implementation plan.

Closed old PR, and reverted in PR #3807

🙌️

Sorry for reopening this, but I'm confused on how to get this working.
I've added a next.config.js to the root (next to the package.json) with the following:

// next.config.js
module.exports = {
  poweredByHeader: false
}

but it doesn't seem to have any effect. A curl -i shows:

X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: same-origin
X-Powered-By: Next.js 5.0.0
Cache-Control: no-store, must-revalidate
Content-Type: text/html; charset=utf-8
Content-Length: 64554
Date: Wed, 21 Mar 2018 12:59:33 GMT
Connection: keep-alive

am I missing anything? Thank you.

Upgrade to next@canary till 5.1 comes out.

@ericat Thank you for providing extra detail via the headers.

This was released in [email protected] which is a pre-release and has yet to hit the master branch (which is at 5.0.0 per your curl). As @timneutkens stated while I was typing (thanks Tim!), you can upgrade ahead of time in your package.json with next@canary (it will look like below):

    "next": "canary",

Please note: That until code gets moved off of canary, it is considered unstable (though keep me honest, Tim).

Your next.config.js file is looking good when it does move!

Ah thank you, must have missed that. Sorry!! 👍 Thanks for the super quick reply.

Was this page helpful?
0 / 5 - 0 ratings