Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,12 @@ import {
readBodyWithSizeLimit,
} from './lib/postponed-request-body'

// Pre-compute Vary header strings at module level to avoid repeated string
// concatenation on every request. These are constant values derived from
// header name constants and never change at runtime.
const STATIC_VARY_HEADER = `${RSC_HEADER}, ${NEXT_ROUTER_STATE_TREE_HEADER}, ${NEXT_ROUTER_PREFETCH_HEADER}, ${NEXT_ROUTER_SEGMENT_PREFETCH_HEADER}`
const STATIC_VARY_HEADER_WITH_NEXT_URL = `${STATIC_VARY_HEADER}, ${NEXT_URL}`

export type FindComponentsResult<
NextModule extends GenericComponentMod = GenericComponentMod,
> = {
Expand Down Expand Up @@ -1995,20 +2001,19 @@ export default abstract class Server<
isAppPath: boolean,
resolvedPathname: string
): void {
const baseVaryHeader = `${RSC_HEADER}, ${NEXT_ROUTER_STATE_TREE_HEADER}, ${NEXT_ROUTER_PREFETCH_HEADER}, ${NEXT_ROUTER_SEGMENT_PREFETCH_HEADER}`
const isRSCRequest = getRequestMeta(req, 'isRSCRequest') ?? false

let addedNextUrlToVary = false

if (isAppPath && this.pathCouldBeIntercepted(resolvedPathname)) {
// Interception route responses can vary based on the `Next-URL` header.
// We use the Vary header to signal this behavior to the client to properly cache the response.
res.appendHeader('vary', `${baseVaryHeader}, ${NEXT_URL}`)
res.appendHeader('vary', STATIC_VARY_HEADER_WITH_NEXT_URL)
addedNextUrlToVary = true
} else if (isAppPath || isRSCRequest) {
// We don't need to include `Next-URL` in the Vary header for non-interception routes since it won't affect the response.
// We also set this header for pages to avoid caching issues when navigating between pages and app.
res.appendHeader('vary', baseVaryHeader)
res.appendHeader('vary', STATIC_VARY_HEADER)
}

if (!addedNextUrlToVary) {
Expand Down
11 changes: 8 additions & 3 deletions packages/next/src/server/request-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,14 @@ export function addRequestMeta<K extends keyof RequestMeta>(
key: K,
value: RequestMeta[K]
) {
const meta = getRequestMeta(request)
meta[key] = value
return setRequestMeta(request, meta)
let meta = request[NEXT_REQUEST_META]
if (meta) {
meta[key] = value
} else {
meta = { [key]: value } as RequestMeta
request[NEXT_REQUEST_META] = meta
}
return meta
}

/**
Expand Down
11 changes: 7 additions & 4 deletions packages/next/src/server/route-modules/app-page/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ import type { UrlWithParsedQuery } from 'url'
import type { IncomingMessage } from 'http'
import { normalizeAppPageRequestUrl } from './normalize-request-url'

// Pre-compute Vary header strings at module level to avoid repeated string
// concatenation on every request.
const STATIC_VARY_HEADER = `${RSC_HEADER}, ${NEXT_ROUTER_STATE_TREE_HEADER}, ${NEXT_ROUTER_PREFETCH_HEADER}, ${NEXT_ROUTER_SEGMENT_PREFETCH_HEADER}`
const STATIC_VARY_HEADER_WITH_NEXT_URL = `${STATIC_VARY_HEADER}, ${NEXT_URL}`

let vendoredReactRSC
let vendoredReactSSR

Expand Down Expand Up @@ -180,18 +185,16 @@ export class AppPageRouteModule extends RouteModule<
resolvedPathname: string,
interceptionRoutePatterns: RegExp[]
): string {
const baseVaryHeader = `${RSC_HEADER}, ${NEXT_ROUTER_STATE_TREE_HEADER}, ${NEXT_ROUTER_PREFETCH_HEADER}, ${NEXT_ROUTER_SEGMENT_PREFETCH_HEADER}`

if (
this.pathCouldBeIntercepted(resolvedPathname, interceptionRoutePatterns)
) {
// Interception route responses can vary based on the `Next-URL` header.
// We use the Vary header to signal this behavior to the client to properly cache the response.
return `${baseVaryHeader}, ${NEXT_URL}`
return STATIC_VARY_HEADER_WITH_NEXT_URL
} else {
// We don't need to include `Next-URL` in the Vary header for non-interception routes since it won't affect the response.
// We also set this header for pages to avoid caching issues when navigating between pages and app.
return baseVaryHeader
return STATIC_VARY_HEADER
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion packages/next/src/server/send-payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export function sendEtagResponse(
return false
}

// Pre-computed constant header name/value pairs to avoid repeated string
// allocation on every response.
const X_POWERED_BY_HEADER = 'X-Powered-By' as const
const X_POWERED_BY_VALUE = 'Next.js' as const

export async function sendRenderResult({
req,
res,
Expand All @@ -52,7 +57,7 @@ export async function sendRenderResult({
}

if (poweredByHeader && result.contentType === HTML_CONTENT_TYPE_HEADER) {
res.setHeader('X-Powered-By', 'Next.js')
res.setHeader(X_POWERED_BY_HEADER, X_POWERED_BY_VALUE)
}

// If cache control is already set on the response we don't
Expand Down
Loading