Skip to content

Commit

Permalink
Catch errors that occur within the stream in the Node adapter (#6935)
Browse files Browse the repository at this point in the history
* Catch errors that occur within the stream in the Node adapter

* Adding a changeset

* Better error message on completely uncaught errors within the stream

* Update test
  • Loading branch information
matthewp authored May 1, 2023
1 parent 649d709 commit c405cef
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/silent-years-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/node': patch
---

Catch errors that occur within the stream in the Node adapter
9 changes: 7 additions & 2 deletions packages/integrations/node/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ async function writeWebResponse(app: NodeApp, res: ServerResponse, webResponse:

res.writeHead(status, Object.fromEntries(headers.entries()));
if (webResponse.body) {
for await (const chunk of responseIterator(webResponse) as unknown as Readable) {
res.write(chunk);
try {
for await (const chunk of responseIterator(webResponse) as unknown as Readable) {
res.write(chunk);
}
} catch(err: any) {
console.error(err?.stack || err?.message || String(err))
res.write('Internal server error');
}
}
res.end();
Expand Down
33 changes: 33 additions & 0 deletions packages/integrations/node/test/errors.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import nodejs from '../dist/index.js';
import { loadFixture } from './test-utils.js';
import { expect } from 'chai';
import * as cheerio from 'cheerio';

describe('Errors', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/errors/',
output: 'server',
adapter: nodejs({ mode: 'standalone' }),
});
await fixture.build();
});
describe('Within the stream', async () => {
let devPreview;

before(async () => {
devPreview = await fixture.preview();
});
after(async () => {
await devPreview.stop();
});
it('when mode is standalone', async () => {
const res = await fixture.fetch('/in-stream');
const html = await res.text();
const $ = cheerio.load(html);

expect($('p').text().trim()).to.equal('Internal server error');
});
});
});
9 changes: 9 additions & 0 deletions packages/integrations/node/test/fixtures/errors/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@test/nodejs-errors",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*",
"@astrojs/node": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
---
<html>
<head>
<title>One</title>
</head>
<body>
<h1>One</h1>
<p>
{Promise.reject('Error in the stream')}
</p>
</body>
</html>
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c405cef

Please sign in to comment.