UNPKG

4.13 kB Markdown View Raw
1---
2title: HTTP Headers
3---
4
5# HTTP Headers
6
7[MODES: framework]
8
9<br/>
10<br/>
11
12## Reading request headers
13
14The `request` sent to route handlers is a standard Web Fetch [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request), so you can read headers directly from the [`request.headers`](https://developer.mozilla.org/en-US/docs/Web/API/Request/headers) property:
15
16```tsx filename=some-route.tsx
17export async function loader({
18 request,
19}: Route.LoaderArgs) {
20 // Standard Headers methods are available
21 const userAgent = request.headers.get("User-Agent");
22 const hasCookies = request.headers.has("Cookie");
23
24 // ...
25}
26```
27
28## Setting response headers
29
30Headers are primarily defined with the route module `headers` export. You can also set headers in `entry.server.tsx`.
31
32### From Route Modules
33
34```tsx filename=some-route.tsx
35import { Route } from "./+types/some-route";
36
37export function headers(_: Route.HeadersArgs) {
38 return {
39 "Content-Security-Policy": "default-src 'self'",
40 "X-Frame-Options": "DENY",
41 "X-Content-Type-Options": "nosniff",
42 "Cache-Control": "max-age=3600, s-maxage=86400",
43 };
44}
45```
46
47You can return either a [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) instance or `HeadersInit`.
48
49### From loaders and actions
50
51When the header is dependent on loader data, loaders and actions can also set headers.
52
53**1. Wrap your return value in `data`**
54
55```tsx lines=[1,8]
56import { data } from "react-router";
57
58export async function loader({ params }: LoaderArgs) {
59 let [page, ms] = await fakeTimeCall(
60 await getPage(params.id),
61 );
62
63 return data(page, {
64 headers: {
65 "Server-Timing": `page;dur=${ms};desc="Page query"`,
66 },
67 });
68}
69```
70
71**2. Return from `headers` export**
72
73Headers from loaders and actions are not sent automatically. You must explicitly return them from the `headers` export.
74
75```tsx
76function hasAnyHeaders(headers: Headers): boolean {
77 return [...headers].length > 0;
78}
79
80export function headers({
81 actionHeaders,
82 loaderHeaders,
83}: HeadersArgs) {
84 return hasAnyHeaders(actionHeaders)
85 ? actionHeaders
86 : loaderHeaders;
87}
88```
89
90One notable exception is `Set-Cookie` headers, which are automatically preserved from `headers`, `loader`, and `action` in parent routes, even without exporting `headers` from the child route.
91
92### Merging with parent headers
93
94Consider these nested routes
95
96```ts filename=routes.ts
97route("pages", "pages-layout-with-nav.tsx", [
98 route(":slug", "page.tsx"),
99]);
100```
101
102If both route modules want to set headers, the headers from the deepest matching route will be sent.
103
104When you need to keep both the parent and the child headers, you need to merge them in the child route.
105
106#### Appending
107
108The easiest way is to simply append to the parent headers. This avoids overwriting a header the parent may have set and both are important.
109
110```tsx
111export function headers({ parentHeaders }: HeadersArgs) {
112 parentHeaders.append(
113 "Permissions-Policy: geolocation=()",
114 );
115 return parentHeaders;
116}
117```
118
119#### Setting
120
121Sometimes it's important to overwrite the parent header. Do this with `set` instead of `append`:
122
123```tsx
124export function headers({ parentHeaders }: HeadersArgs) {
125 parentHeaders.set(
126 "Cache-Control",
127 "max-age=3600, s-maxage=86400",
128 );
129 return parentHeaders;
130}
131```
132
133You can avoid the need to merge headers by only defining headers in "leaf routes" (index routes and child routes without children) and not in parent routes.
134
135### From `entry.server.tsx`
136
137The `handleRequest` export receives the headers from the route module as an argument. You can append global headers here.
138
139```tsx
140export default async function handleRequest(
141 request,
142 responseStatusCode,
143 responseHeaders,
144 routerContext,
145 loadContext,
146) {
147 // set, append global headers
148 responseHeaders.set(
149 "X-App-Version",
150 routerContext.manifest.version,
151 );
152
153 return new Response(await getStream(), {
154 headers: responseHeaders,
155 status: responseStatusCode,
156 });
157}
158```
159
160If you don't have an `entry.server.tsx` run the `reveal` command:
161
162```shellscript nonumber
163react-router reveal
164```
165
\No newline at end of file