跳到內容

headers

標頭允許您在指定路徑上,針對傳入請求的回應設定自訂 HTTP 標頭。

若要設定自訂 HTTP 標頭,您可以使用 next.config.js 中的 headers

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/about',
        headers: [
          {
            key: 'x-custom-header',
            value: 'my custom header value',
          },
          {
            key: 'x-another-custom-header',
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

headers 是一個非同步函式,預期會傳回一個陣列,其中包含具有 sourceheaders 屬性的物件

  • source 是傳入請求路徑模式。
  • headers 是一個回應標頭物件陣列,具有 keyvalue 屬性。
  • basePathfalseundefined - 若為 false,則在匹配時不會包含 basePath,僅適用於外部重新導向。
  • localefalseundefined - 是否在匹配時不應包含語系。
  • has 是一個 has 物件 陣列,具有 typekeyvalue 屬性。
  • missing 是一個 missing 物件 陣列,具有 typekeyvalue 屬性。

標頭會在檔案系統(包含頁面和 /public 檔案)之前檢查。

標頭覆寫行為

如果兩個標頭匹配相同的路徑並設定相同的標頭鍵,則最後一個標頭鍵將覆寫第一個。使用以下標頭,路徑 /hello 將導致標頭 x-helloworld,因為最後設定的標頭值為 world

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'x-hello',
            value: 'there',
          },
        ],
      },
      {
        source: '/hello',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

路徑匹配

允許路徑匹配,例如 /blog/:slug 將匹配 /blog/hello-world (沒有巢狀路徑)

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug',
        headers: [
          {
            key: 'x-slug',
            value: ':slug', // Matched parameters can be used in the value
          },
          {
            key: 'x-slug-:slug', // Matched parameters can be used in the key
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

萬用字元路徑匹配

若要匹配萬用字元路徑,您可以在參數後使用 *,例如 /blog/:slug* 將匹配 /blog/a/b/c/d/hello-world

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:slug*',
        headers: [
          {
            key: 'x-slug',
            value: ':slug*', // Matched parameters can be used in the value
          },
          {
            key: 'x-slug-:slug*', // Matched parameters can be used in the key
            value: 'my other custom header value',
          },
        ],
      },
    ]
  },
}

Regex 路徑匹配

若要匹配 Regex 路徑,您可以將 Regex 包裹在參數後的括號中,例如 /blog/:slug(\\d{1,}) 將匹配 /blog/123 但不匹配 /blog/abc

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/blog/:post(\\d{1,})',
        headers: [
          {
            key: 'x-post',
            value: ':post',
          },
        ],
      },
    ]
  },
}

以下字元 (){}:*+? 用於 Regex 路徑匹配,因此當在 source 中用作非特殊值時,必須透過在其前面新增 \\ 來逸出

next.config.js
module.exports = {
  async headers() {
    return [
      {
        // this will match `/english(default)/something` being requested
        source: '/english\\(default\\)/:slug',
        headers: [
          {
            key: 'x-header',
            value: 'value',
          },
        ],
      },
    ]
  },
}

若要僅在標頭、Cookie 或查詢值也匹配 has 欄位,或不匹配 missing 欄位時套用標頭,可以使用 has 欄位或 missing 欄位。 source 和所有 has 項目都必須匹配,且所有 missing 項目都不得匹配,標頭才會套用。

hasmissing 項目可以有以下欄位

  • typeString - 必須是 headercookiehostquery 其中之一。
  • keyString - 要匹配的選定類型中的鍵。
  • valueStringundefined - 要檢查的值,如果未定義,則任何值都將匹配。可以使用類似字串的 Regex 來捕捉值的特定部分,例如,如果 first-(?<paramName>.*) 的值用於 first-second,則 second 將可透過 :paramName 在目的地中使用。
next.config.js
module.exports = {
  async headers() {
    return [
      // if the header `x-add-header` is present,
      // the `x-another-header` header will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-add-header',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: 'hello',
          },
        ],
      },
      // if the header `x-no-header` is not present,
      // the `x-another-header` header will be applied
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-no-header',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: 'hello',
          },
        ],
      },
      // if the source, query, and cookie are matched,
      // the `x-authorized` header will be applied
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // the page value will not be available in the
            // header key/values since value is provided and
            // doesn't use a named capture group e.g. (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        headers: [
          {
            key: 'x-authorized',
            value: ':authorized',
          },
        ],
      },
      // if the header `x-authorized` is present and
      // contains a matching value, the `x-another-header` will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: ':authorized',
          },
        ],
      },
      // if the host is `example.com`,
      // this header will be applied
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        headers: [
          {
            key: 'x-another-header',
            value: ':authorized',
          },
        ],
      },
    ]
  },
}

具有 basePath 支援的標頭

當搭配 basePath 支援 使用標頭時,每個 source 都會自動加上 basePath 前綴,除非您在標頭中新增 basePath: false

next.config.js
module.exports = {
  basePath: '/docs',
 
  async headers() {
    return [
      {
        source: '/with-basePath', // becomes /docs/with-basePath
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        source: '/without-basePath', // is not modified since basePath: false is set
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
        basePath: false,
      },
    ]
  },
}

具有 i18n 支援的標頭

當搭配 i18n 支援 使用標頭時,每個 source 都會自動加上前綴以處理已設定的 locales,除非您在標頭中新增 locale: false。 如果使用 locale: false,您必須在 source 前面加上語系,才能正確匹配。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'fr', 'de'],
    defaultLocale: 'en',
  },
 
  async headers() {
    return [
      {
        source: '/with-locale', // automatically handles all locales
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // does not handle locales automatically since locale: false is set
        source: '/nl/with-locale-manual',
        locale: false,
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // this matches '/' since `en` is the defaultLocale
        source: '/en',
        locale: false,
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
      {
        // this gets converted to /(en|fr|de)/(.*) so will not match the top-level
        // `/` or `/fr` routes like /:path* would
        source: '/(.*)',
        headers: [
          {
            key: 'x-hello',
            value: 'world',
          },
        ],
      },
    ]
  },
}

Cache-Control

Next.js 為真正不可變的資產設定 public, max-age=31536000, immutableCache-Control 標頭。它無法被覆寫。這些不可變的檔案在檔案名稱中包含 SHA 雜湊,因此可以安全地無限期快取。例如,靜態圖片匯入。您無法在 next.config.js 中為這些資產設定 Cache-Control 標頭。

但是,您可以為其他回應或資料設定 Cache-Control 標頭。

如果您需要重新驗證已靜態產生的頁面快取,您可以透過在頁面的 getStaticProps 函式中設定 revalidate 屬性來完成。

若要快取來自 API 路由的回應,您可以使用 res.setHeader

pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
type ResponseData = {
  message: string
}
 
export default function handler(
  req: NextApiRequest,
  res: NextApiResponse<ResponseData>
) {
  res.setHeader('Cache-Control', 's-maxage=86400')
  res.status(200).json({ message: 'Hello from Next.js!' })
}

您也可以在 getServerSideProps 內使用快取標頭 (Cache-Control) 來快取動態回應。例如,使用 stale-while-revalidate

pages/index.tsx
import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'
 
// This value is considered fresh for ten seconds (s-maxage=10).
// If a request is repeated within the next 10 seconds, the previously
// cached value will still be fresh. If the request is repeated before 59 seconds,
// the cached value will be stale but still render (stale-while-revalidate=59).
//
// In the background, a revalidation request will be made to populate the cache
// with a fresh value. If you refresh the page, you will see the new value.
export const getServerSideProps = (async (context) => {
  context.res.setHeader(
    'Cache-Control',
    'public, s-maxage=10, stale-while-revalidate=59'
  )
 
  return {
    props: {},
  }
}) satisfies GetServerSideProps

選項

CORS

跨來源資源共享 (CORS) 是一項安全功能,可讓您控制哪些網站可以存取您的資源。您可以設定 Access-Control-Allow-Origin 標頭,以允許特定來源存取您的API 端點.

async headers() {
    return [
      {
        source: "/api/:path*",
        headers: [
          {
            key: "Access-Control-Allow-Origin",
            value: "*", // Set your origin
          },
          {
            key: "Access-Control-Allow-Methods",
            value: "GET, POST, PUT, DELETE, OPTIONS",
          },
          {
            key: "Access-Control-Allow-Headers",
            value: "Content-Type, Authorization",
          },
        ],
      },
    ];
  },

X-DNS-Prefetch-Control

此標頭 控制 DNS 預先擷取,允許瀏覽器主動對外部連結、圖片、CSS、JavaScript 等執行網域名稱解析。此預先擷取在背景中執行,因此 DNS 更有可能在需要參考項目時解析。這減少了使用者點擊連結時的延遲。

{
  key: 'X-DNS-Prefetch-Control',
  value: 'on'
}

Strict-Transport-Security

此標頭 通知瀏覽器應僅使用 HTTPS 而非 HTTP 存取。使用以下設定,所有現在和未來的子網域都將使用 HTTPS,max-age 為 2 年。這會阻止存取只能透過 HTTP 提供的頁面或子網域。

如果您部署到 Vercel,則此標頭不是必要的,因為它會自動新增至所有部署,除非您在 next.config.js 中宣告 headers

{
  key: 'Strict-Transport-Security',
  value: 'max-age=63072000; includeSubDomains; preload'
}

X-Frame-Options

此標頭 指示是否應允許網站顯示在 iframe 中。這可以防止點擊劫持攻擊。

此標頭已被 CSP 的 frame-ancestors 選項取代,後者在現代瀏覽器中具有更好的支援(有關設定詳細資訊,請參閱內容安全策略)。

{
  key: 'X-Frame-Options',
  value: 'SAMEORIGIN'
}

Permissions-Policy

此標頭 允許您控制瀏覽器中可以使用哪些功能和 API。它以前名為 Feature-Policy

{
  key: 'Permissions-Policy',
  value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()'
}

X-Content-Type-Options

此標頭 防止瀏覽器在未明確設定 Content-Type 標頭時嘗試猜測內容類型。這可以防止允許使用者上傳和共享檔案的網站遭受 XSS 漏洞利用。

例如,使用者嘗試下載圖片,但將其視為不同的 Content-Type,例如可執行檔,這可能是惡意的。此標頭也適用於下載瀏覽器擴充功能。此標頭唯一有效的值是 nosniff

{
  key: 'X-Content-Type-Options',
  value: 'nosniff'
}

Referrer-Policy

此標頭 控制從目前網站(來源)導航到另一個網站時,瀏覽器包含多少資訊。

{
  key: 'Referrer-Policy',
  value: 'origin-when-cross-origin'
}

Content-Security-Policy

深入瞭解如何將內容安全策略新增至您的應用程式。

版本歷史

版本變更
v13.3.0新增 missing
v10.2.0新增 has
v9.5.0新增標頭。