-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Direct fetch is incompatible with express.js #328
Comments
What would be the best way to solve this issue?
|
Using this minimal reproduction to followup: import express from 'express';
import { createFetch, createCall } from "unenv/runtime/fetch/index"; // [email protected]
const app = express().use('/test', (req, res) => {
try {
res.setHeader('vary', 'test');
res.send('Hello World')
} catch (err) {
console.error(err)
throw err
}
})
const serverFetch = createFetch(createCall(app));
const res = await serverFetch("/test", {});
console.log({
headers: res.headers.entries(),
body: await res.text()
})
Ideally, express should use the runtime Alternatively we could make unenv polyfill compat by exposing |
I was thinking that the best way would be that in the node preset, we just alias Why use the polyfill when have the natives available?
The problem is they are doing some weird thing instantiating request and response before runtime fetch, so you can add your own methods to them. Their approach is bad practice all over really, they should have just exposed an object and used object assign on req and res to add the methods without messing with prototypes. I opened expressjs/express#6047 which would fix this by stopping the prototype inheritance to only the methods added to the express req and res But I still think unenv should not polyfill those in the node preset, if I am on node, I expect it to behave using the native and not polyfills |
Node.js native We are emulating an HTTP request without actually making a network round trip (otherwise you need to listen an express server and fetch with absolute URL. relative URL fetch is also not supported by node on server alone -- which is your case).
|
Right, it's an emulation taht uses the polyfill, but at the end of the local request, it is expected to be a server running on the env set by the preset, so if it has the node preset, it means the server at the end normally works on the native http implementation, it's expected to have the exact same behavior on the direct call, and having a mix of sometimes the native implementation and sometimes the polyfill in res and req, based on if it's a direct request or not leads to those edge cases I guess this could be addressed by having a different polyfill for node, where we just override what we need to make it work and alias to that instead in the preset Something like export class IncomingMessage extends http.IncomingMessage { // Extend the native implementation
// Override some stuff
} I can see a way to avoid the duplicated code by having in the original export class ServerResponse extends NodeServerResponseOrWritable Where NodeServerResponseOrWritable will resolve to either Otherwise the parameters you mention are not required and
|
No actually the util does not assumes on a running server that's the whole point/benefit of direct fetch util.
While i agree that it could be one possible solution to extend We have Node.js, Bun, Deno, (and workerd maybe someday?) with at least 3 different (internal) implementations of The root cause of express incompatibility is actually a wrong mix that express tries to call It probably makes sense for |
With all this said, if you still like to invest time on making a But it will be a long path and we need someone to constantly maintain it ensuring will be compatible with future runtime changes. This time could be spent on better places such as stream support (#365) I can invite you to another effort we are trying to make sure unenv impl is same as Node.js for critical modules as as |
Environment
Nuxt with default node env
Reproduction
Describe the bug
When sending a local request to an express server using fetch, a server error occurs
Additional context
This is very problematic in nuxt with useFetch and a legacy endpoint that uses an express server behind the scenes (This issue took me about 20h to debug because it's such a complex chain of events to follow and the errors hidden behind 3 layers could not even be sent properly because the response object was broken)
It seems the problem is that unenv's fetch always uses its internal node/http/request,response even if build with the node env preset and this is problematic because then local requests behave differently than external requests
https://github.com/unjs/unenv/blob/main/src/runtime/fetch/call.ts#L1-L2
unenv's fetch is then used by nitro even if env is set to node
https://github.com/unjs/nitro/blob/a399e189576d4c18d7f837bd454e0503e1f53980/src/types/runtime/nitro.ts#L7
Logs
No response
The text was updated successfully, but these errors were encountered: