-
-
Save cramforce/12e58aea2920ae80159f42be451e8027 to your computer and use it in GitHub Desktop.
| import { NextResponse } from "next/server"; | |
| import type { NextRequest } from "next/server"; | |
| const SCRIPT_TAG = '<script async src="/feedback-bootstrap.js"></script>'; | |
| export async function middleware(request: NextRequest) { | |
| // Skip requests not looking for html. | |
| const accept = request.headers.get("accept") || ""; | |
| if (!accept) { | |
| console.log("Request headers", request.headers); | |
| } | |
| if (!accept || !accept.startsWith("text/html")) { | |
| return NextResponse.next(); | |
| } | |
| const middlewareResponse = NextResponse.next(); | |
| // Skip redirects, etc. | |
| if (middlewareResponse.status > 200) { | |
| return middlewareResponse; | |
| } | |
| // We want to change the response, and that means we have to fetch it ourselves. | |
| const originResponse = await fetch(request); | |
| // Response doesn't look like HTML, skip! | |
| const contentType = originResponse.headers.get("content-type"); | |
| if (!contentType) { | |
| console.log("Origin response headers", originResponse.headers); | |
| } | |
| if (!contentType || !contentType.startsWith("text/html")) { | |
| return originResponse; | |
| } | |
| let rewritten; | |
| if (originResponse.body.getReader) { | |
| console.log("Using the streaming API"); | |
| const reader = originResponse.body.getReader(); | |
| rewritten = new ReadableStream({ | |
| start(controller) { | |
| function push() { | |
| return reader.read().then(({ done, value }) => { | |
| if (done) { | |
| // Append the script tag. | |
| controller.enqueue(new TextEncoder().encode(SCRIPT_TAG)); | |
| controller.close(); | |
| return; | |
| } | |
| controller.enqueue(value); | |
| push(); | |
| }); | |
| } | |
| push(); | |
| }, | |
| }); | |
| } else { | |
| // It appears that originResponse.body.getReader is null and so we cannot stream the | |
| // addition. | |
| const text = await originResponse.text(); | |
| // Dumping it to the end is simple and works. | |
| rewritten = text + SCRIPT_TAG; | |
| } | |
| return new Response(rewritten, { | |
| headers: new Headers(originResponse.headers), | |
| status: originResponse.status, | |
| statusText: originResponse.statusText, | |
| }); | |
| } |
The idea is that if other middlewares do a redirect, then this one should do nothing. It would likely also check whether there is a body in case the middleware actually responded.
But NextResponse.next() doesn't actually run anything else. It's just a static object (so that check will always be false):
static next() {
return new NextResponse(null, {
headers: {
'x-middleware-next': '1',
},
})
}
It's used to check the response at the end of the middleware call to know what to do next. I think it's mostly meant to be used if you want to let the request fall through, but attach some extra headers.
As far as I can see the streaming interface on the fetch response is broken.
Yeah, it's a middleware issue, we have a workaround cleanResponseBody method in Live to get the correct ReadableStream (currently it returns a Node.js stream)
--
The rest looks good. Only worry here is if the user has an existing top-level middleware, I don't know how this will play out (how do we merge them)
This is pretty much exactly the way I implemented it locally as well, only difference was the streaming
I think that is actually exactly what we want. We do need to monitor when
location.hrefchanges and update the comment state.The idea is that if other middlewares do a redirect, then this one should do nothing. It would likely also check whether there is a body in case the middleware actually responded.
See comment. As far as I can see the streaming interface on the fetch response is broken. Otherwise we should absolutely do this.