Simplify res.end()
proxy logic — current implementation adds complexity with little real-world benefit
#1037
Labels
Problem
The current implementation proxies
res.end()
in a way that tries to ensure the session is saved before completing the response. However, this logic is complex, fragile, and not reliable in real-world usage, particularly with redirects and concurrent browser requests.Background
The proxy behavior works roughly like this:
res.end()
, it writes all but the last byte.res.write()
triggersres.writeHead()
, buffering headers.session.save()
orsession.touch()
is called.res.end()
.This seems designed to ensure session data is saved before the client makes another request. It may help in tests, but it breaks down in browsers for several reasons:
In practice, this complexity doesn't prevent session races and makes the code in the library error prone and harder to maintain.
Example Workaround
Today, to ensure a session is saved before a redirect, we have to do this manually:
This workaround works, but it exposes the fact that the
res.end()
proxy doesn't reliably help in the redirect case, which is likely one that users were hoping to be solved.Proposal
I propose removing the
res.end()
proxy entirely and replacing it with much simpler logic.Option 1: Delay header send
This ensures that the session is saved before headers are sent. Because
res.write()
andres.end()
call this from within their internal flow, we still need to add small proxies there, since we cannot delay execution without async/await. See #704 for some details.As a benefit, errors can be thrown before the response is committed and thus should result 500 as the response.
Option 2: Async session save
This approach decouples session saving from the response entirely. While there's a risk the session isn't saved before the next request, that’s already possible today. More importantly, this avoids unnecessary complexity.
Some of the session races condition could be mitigated or logged in the store (e.g., compare and swap or diff-based updates), which are conceptually impossible in this library.
Why This Matters
location
header is sent to the browser #157.express-session
easier to use and maintain, while encouraging explicit and predictable session handling by developers.Conclusion
I believe we should remove the complex
res.end()
proxy logic. In addition, we should document best practices clearly (e.g., callingsession.save()
manually before redirects). I'm happy to help with an implementation or documentation update if this direction sounds good.What do you think?
Do you find errors in my understand on reasoning?
The text was updated successfully, but these errors were encountered: