Admin returns 404 in production mode when `Accept` header is missing

default discord avatar
hdodov
9 months ago
1 2

Bug Report

I use AWS Elastic Load Balancing and was surprised to see that my server is unhealthy, yet handles requests without a problem. Upon further investigation, I discovered that the reason for that is the absence of the Accept header. I logged on the machine and:

  • curl -XGET -I localhost:80/admin (which has Accept: */* by default) returns HTTP 200
  • curl -XGET -I localhost:80/admin -H "Accept:" (Accept is set to empty) returns HTTP 404

This header is lacking in the raw HTTP request that the load balancer sends:

GET /admin HTTP/1.1
Host: 172.31.32.240
Connection: close
User-Agent: ELB-HealthChecker/2.0
Accept-Encoding: gzip, compressed

…which results in a 404 and "Severe" state in Elastic Beanstalk.


Then, I tested locally and found out that this only happens in production mode. In development, it returns status code 200, regardless of Accept. What appears to be fixing it is the Webpack middleware. If I comment out this line:

ctx.express.use(initWebpack(ctx.config));

…I can get the same behavior in development mode as well.

Steps to Reproduce

  1. Run npm run build, then npm run serve to run Payload in production mode
  2. curl -i localhost:3000/admin -H "Accept:"
  3. You'll see HTTP/1.1 404 Not Found with the Express error Cannot GET /admin

Note, however, that requesting a file from the build folder like curl -XGET -I localhost:3000/admin/styles.css -H "Accept:" correctly returns status 200.

Expected behavior

Requests to /admin should always return status code 200.

Other Details

Payload version: 1.3.0

  • discord user avatar
    jmikrut
    Payload Team
    9 months ago

    Hey @hdodov — we just looked into this in-depth and I have some explanations for you as well as a potential solution.

    In production, we are simply leveraging express.static to serve static files. The Accept header is necessary to be able to consume html, etc. from a server response, and being that your health check request does not specify it, Express does not return with any results - thus 404.

    This is not something that Payload can control, and further, express.static does not have any options for how to treat the Accept header.

    Instead, what you could do would be to point your health check to a custom route that you've opened, like /health-check and have your route return a 200.

    Either that, or you could figure out if there is a way to modify the health check request that you are sending from Elastic Load Balancing to add a header to that request, which should be possible. Because really what you're telling Elastic to do is to hit a static file, with no Accept header, which will rightly 404, as there is no Accept header allowing html response types.

    Does that make sense?

    1 reply
  • default discord avatar
    hdodov
    9 months ago

    Yep, adding a /health route is exactly what I did. I just thought that maybe it's an issue with Payload, rather than Express.

  • discord user avatar
    denolfe
    Payload Team
    9 months ago

    Looking into this one @hdodov. I was able to recreate.

Open the post
Continue the discussion in GitHub
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.