Route matching differs between local and prod

I’m using itty-router. I have a worker that declares a single route. Locally, I’m able to hit that route and get the response. When deployed, however, that route returns 404 as if not implemented.

router.get('/user%2fpackage', () => new Response(null, { status: 200 }))
  • I confirm that is the identical route.
  • I confirm that is the same worker code.

One thing that may be causing this, my route has an escaped component %2f present:

  • GET user%2fpackage

That is the requirement for my router, I must not change that. There still seems to be an issue with route matching since dev and prod exhibit different behavior. This suggests that the production environment has additional logic on top of route matching that may be interfering here.

Does Cloudflare production has some sort of URL escaping/normalization built-in for workers? How can I ensure my worker handles requests in terms of path matching identically in production?

1 Like

Most likely related to this:

I vaguely recall seeing somewhere last week that Cloudflare will be implementing a improved URL parser soon, so that should fix these kind of issues then.

I’ve found the culprit. For some reason, the same URL is encoded differently on local and on prod:

  • local: / becomes %2f
  • prod: / becomes %2F

I’ve adjusted my route path to be case-insensitive and that fixed the issue.

1 Like

Yes, coming very soon:

1 Like

Glad you got this resolved!

Just a note, and it’s very possible you left it out of your example snippet for ease of translation, but itty-router-extras would turn that new Response(null, { status: 200 }) into status(200) for further code simplification. Itty-router was designed as a single-purpose utility, with all the real quality of life improvements (middlewares and response utilities) being shuffled out to the “extras” library. I use both together 100% of the time because I really don’t want to have to manually construct JSON responses (99% of my handlers).

Hope this helps!