Closed arthuredelstein closed 1 year ago
Thanks @arthuredelstein - taking a look now! Fantastic repro steps!
So... this looks like a side effect of environments and how they handle (or don't) the direct serialization of the Headers
class (which request.headers
will typically be).
To test this, try accessing a known header directly:
router
// this should work everywhere
.get('/direct', () => request.headers.get('user-agent'))
// so should this (but as an array)
.get('/entries', () => [ ...request.headers.entries() ])
These should both work, regardless of environment I suspect.
As it stands, request.headers
is a read-only property (of the Request
API), limiting our ability to "reform" the attribute, even with a little middleware. To work around it, you can either:
headersAsObject
)headers
and redirect it elsewhere.For example, these both work:
// GET HEADERS AS OBJECT (different attribute)
.get('/headers-middleware',
(request) => {
const headers = request.headersAsObject = {}
for (let [key, value] of request.headers.entries()) {
headers[key] = value
}
},
({ headersAsObject }) => headersAsObject
)
// GET HEADERS AS OBJECT (via Proxy)
.get('/headers-middleware-direct',
(request) => {
const headers = request.headersAsObject = {}
for (let [key, value] of request.headers.entries()) {
headers[key] = value
}
request.proxy = new Proxy(request.proxy || request, {
get: (obj, prop) => prop === 'headers' ? headers : obj[prop]
})
},
({ headers }) => headers
)
I should caveat that adding middleware like the last example (that proxies over the request.headers) would break the standard request.headers.get('some-header')
API which is commonly used, so use with care!
Anyway, as it stands, this is perhaps something to note in our docs, but not a bug to fix - rather just an anomaly of using the web standards API! :)
I see! Makes sense @kwhitley. Thank you very much for figuring it out and explaining it.
Happy to! I've noticed something similar in my own tinkering, yet never really gave it the actual thought/investigation to realize why exactly that was happening. I assumed it was something of a serialization issue, but never confirmed - so it was a fun little learning experience for both of us! :)
Describe the Issue
I want to return request.headers, and this works in Node.js, but it doesn't work in Cloudflare.
Example Router Code
Steps to Reproduce
Steps to reproduce the behavior:
node_compat = true
towrangler.toml
.node src/worker.js
b.wrangler dev
c.wrangler dev --remote
d.wrangler deploy
Expected Behavior
A JSON object with a number of header key-values. For example, with node.js I see:
Actual Behavior
Node.js gives results as expected. On Cloudflare, the page displays only an empty JSON object,
{}
.