-
Notifications
You must be signed in to change notification settings - Fork 66
feat: always respond res.body
#262
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
Conversation
f3ce91a
to
fe5fa5c
Compare
fe5fa5c
to
4d70f93
Compare
@yusukebe |
res.body
) { | ||
outgoing.writeHead(res.status, resHeaderRecord) | ||
flushHeaders(outgoing) | ||
// In the case of synchronous responses, usually a maximum of two readings is done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a simple and good idea!
Hi @usualoma This PR's idea makes sense, and the implementation is well done!
Okay! By the way, I've considered those cases, but I couldn't find a good example. Can you imagine the real-world cases? |
Works great solving #260 Tested on:
|
I also tested some patterns that include returning streaming responses. They work great. |
An app that changes resultsTypical examples of apps that change results are as follows. When returning (Content-Length-less) text/html with a slight delay, the main branch automatically added Cotent-Length, but this branch no longer does so. I think this situation is possible with certain types of proxies. However, this does not normally occur when using hono's proxy helper with Node.js. Are there any real-world applications that return text/html without a Content-Length header, with a slight delay? If so, is it expected that these applications automatically add a Content-Length header? I am not sure about this point. (If such applications exist, they are likely very rare.) app.get(
'/',
() => new Response(new ReadableStream({
async start(controller) {
await new Promise((resolve) => setTimeout(resolve, 100))
controller.enqueue(new TextEncoder().encode('Hello, world!'))
controller.close()
},
}), {
headers: {
'Content-Type': 'text/html',
},
})
)
serve(
{
fetch: app.fetch,
port: 3000,
overrideGlobalObjects: false,
},
(info) => {
console.log(`Server is running on http://localhost:${info.port}`)
},
) main branch
this branch
|
There may be use cases where the current main branch behavior is fine, but I think this pull request branch is simpler, makes more sense, and is easier for users to control. (If Content-Length is necessary, users can just add it themselves.) |
@usualoma could this affect the performance? |
When using node-server, the typical response for For requests that pass through the changed section, the bottleneck is likely to be in a different section. Furthermore, the amount of computation should not increase after the change, so there should be no impact. I will measure it when I have time. |
Hey @usualoma Thank you for the reply!
I totally agree you mentioned. This PR's implementation is simple. I think that, in the previous implementation, determining whether or not it was a stream based on the value of resHeaderRecord is not the best implementation.
I also think that this is a rare case, and we don't need to worry about it. We can include it in the next minor version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Looks good to me! If it doesn't have a performance issue, I can merge this. |
benchmarksI ran benchmarks on the following items and found no performance degradation due to this change. appconst app = new Hono()
app.get('/', () => {
const res = new Response('foo')
res.body // create original globalThis.Response
return res
}) result with
|
Great that it is resolving without performance degradation! Let's go with this. Thank you so much! |
Hi @usualoma Unfortunately, the test fails in https://github.com/honojs/node-server/actions/runs/16546886371/job/46795876085 The error occurs in the |
fixes #260
What is this?
The method of extracting the body from the response, which was determined by a fixed (somewhat environment-specific) rule based on the response header, will be determined by adding a point for whether it is sent asynchronously.
This change may (rarely) cause behavior changes, so it is recommended to release a minor version (or major version).
Reading the current code
The following code to be changed has detailed comments explaining “How,” but there are no comments explaining “Why.”
node-server/src/listener.ts
Lines 125 to 161 in 29a19ae
This code is a bit complex because it was written with great care to take into account x-accel-buffering and other factors specific to the (nginx) environment, but the reason for ‘Why’ is simple: “We want to determine whether to automatically add Content-Length to the response based on the header.”
Synchronous reading of data from
res.body
(a ReadableStream)When reading from
res.body
of a response generated likenew Response(text)
, it is usually as follows (in node.js). If Content-Length can be added to this result, it will be possible to determine the actual result rather than relying on a specific environment as is currently the case. This will also solve the problem in #260.