getRequestHandler vs render
app.getRequestHandler returns a request handler which we can use to parse all HTTP requests. app.render checks if static assets need to serve. It also checks if the page requested is a blocked/internal page. After those checks pass, Next.js also use the same request handler that we will get from app.getRequestHandler. If we use request handler directly, we won’t get those checks and run into issues which we need to handle it manually.
Here are parts of the source code that deal with custom server. I hope it make the answer a bit more clear.
// next/next-server/server/next-server.ts
// This function expose a private method, which used by render
public getRequestHandler() {
return this.handleRequest.bind(this)
}
// render method
public async render() {
// .... more code
// check if server needs to handle static files
if (
!query._nextDataReq &&
(url.match(/^\/_next\//) ||
(this.hasStaticDir && url.match(/^\/static\//)))
) {
return this.handleRequest(req, res, parsedUrl)
}
// check the requested page is a internal/blocked page
if (isBlockedPage(pathname)) {
return this.render404(req, res, parsedUrl)
}
const html = await this.renderToHTML(req, res, pathname, query)
// Request was ended by the user
if (html === null) {
return
}
// respond with rendered HTML
return this.sendHTML(req, res, html)
}
Path & Query
I think Next.js query is a bit different from URL query strings. You can have a route like this '/a' and pass in a query object without adding those query to your URL.
This is my best effort to answer the question. Hopefully, I can provide some help.
Reference:
https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/next-server.ts