diff --git a/packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json b/packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json index 5cfed134b98..44bea147622 100644 --- a/packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json +++ b/packages/docs/src/routes/api/qwik-city-middleware-request-handler/api.json @@ -279,7 +279,7 @@ } ], "kind": "Interface", - "content": "```typescript\nexport interface RequestEventBase \n```\n\n\n| Property | Modifiers | Type | Description |\n| --- | --- | --- | --- |\n| [basePathname](#) | readonly | string | The base pathname of the request, which can be configured at build time. Defaults to /. |\n| [cacheControl](#) | readonly | (cacheControl: [CacheControl](#cachecontrol)) => void |

Convenience method to set the Cache-Control header.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

|\n| [clientConn](#) | readonly | [ClientConn](#clientconn) | Provides information about the client connection, such as the IP address and the country the request originated from. |\n| [cookie](#) | readonly | [Cookie](#cookie) |

HTTP request and response cookie. Use the get() method to retrieve a request cookie value. Use the set() method to set a response cookie value.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies

|\n| [env](#) | readonly | [EnvGetter](#envgetter) | Platform provided environment variables. |\n| [headers](#) | readonly | Headers |

HTTP response headers. Notice it will be empty until you first add a header. If you want to read the request headers, use request.headers instead.

https://developer.mozilla.org/en-US/docs/Glossary/Response\\_header

|\n| [method](#) | readonly | string |

HTTP request method.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods

|\n| [params](#) | readonly | Readonly<Record<string, string>> | URL path params which have been parsed from the current url pathname segments. Use query to instead retrieve the query string search params. |\n| [parseBody](#) | readonly | () => Promise<unknown> |

This method will check the request headers for a Content-Type header and parse the body accordingly. It supports application/json, application/x-www-form-urlencoded, and multipart/form-data content types.

If the Content-Type header is not set, it will return null.

|\n| [pathname](#) | readonly | string |

URL pathname. Does not include the protocol, domain, query string (search params) or hash.

https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname

|\n| [platform](#) | readonly | PLATFORM | Platform specific data and functions |\n| [query](#) | readonly | URLSearchParams |

URL Query Strings (URL Search Params). Use params to instead retrieve the route params found in the url pathname.

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

|\n| [request](#) | readonly | Request | HTTP request information. |\n| [sharedMap](#) | readonly | Map<string, any> | Shared Map across all the request handlers. Every HTTP request will get a new instance of the shared map. The shared map is useful for sharing data between request handlers. |\n| [signal](#) | readonly | AbortSignal | Request's AbortSignal (same as request.signal). This signal indicates that the request has been aborted. |\n| [url](#) | readonly | URL | HTTP request URL. |", + "content": "```typescript\nexport interface RequestEventBase \n```\n\n\n| Property | Modifiers | Type | Description |\n| --- | --- | --- | --- |\n| [basePathname](#) | readonly | string | The base pathname of the request, which can be configured at build time. Defaults to /. |\n| [cacheControl](#) | readonly | (cacheControl: [CacheControl](#cachecontrol), target?: CacheControlTarget) => void |

Convenience method to set the Cache-Control header. Depending on your CDN, you may want to add another cacheControl with the second argument set to CDN-Cache-Control or any other value (we provide the most common values for auto-complete, but you can use any string you want).

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control and https://qwik.builder.io/docs/caching/\\#CDN-Cache-Controls for more information.

|\n| [clientConn](#) | readonly | [ClientConn](#clientconn) | Provides information about the client connection, such as the IP address and the country the request originated from. |\n| [cookie](#) | readonly | [Cookie](#cookie) |

HTTP request and response cookie. Use the get() method to retrieve a request cookie value. Use the set() method to set a response cookie value.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies

|\n| [env](#) | readonly | [EnvGetter](#envgetter) | Platform provided environment variables. |\n| [headers](#) | readonly | Headers |

HTTP response headers. Notice it will be empty until you first add a header. If you want to read the request headers, use request.headers instead.

https://developer.mozilla.org/en-US/docs/Glossary/Response\\_header

|\n| [method](#) | readonly | string |

HTTP request method.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods

|\n| [params](#) | readonly | Readonly<Record<string, string>> | URL path params which have been parsed from the current url pathname segments. Use query to instead retrieve the query string search params. |\n| [parseBody](#) | readonly | () => Promise<unknown> |

This method will check the request headers for a Content-Type header and parse the body accordingly. It supports application/json, application/x-www-form-urlencoded, and multipart/form-data content types.

If the Content-Type header is not set, it will return null.

|\n| [pathname](#) | readonly | string |

URL pathname. Does not include the protocol, domain, query string (search params) or hash.

https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname

|\n| [platform](#) | readonly | PLATFORM | Platform specific data and functions |\n| [query](#) | readonly | URLSearchParams |

URL Query Strings (URL Search Params). Use params to instead retrieve the route params found in the url pathname.

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

|\n| [request](#) | readonly | Request | HTTP request information. |\n| [sharedMap](#) | readonly | Map<string, any> | Shared Map across all the request handlers. Every HTTP request will get a new instance of the shared map. The shared map is useful for sharing data between request handlers. |\n| [signal](#) | readonly | AbortSignal | Request's AbortSignal (same as request.signal). This signal indicates that the request has been aborted. |\n| [url](#) | readonly | URL | HTTP request URL. |", "editUrl": "https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/middleware/request-handler/types.ts", "mdFile": "qwik-city.requesteventbase.md" }, diff --git a/packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.md b/packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.md index b8a20e49a8f..f7638d9a9f9 100644 --- a/packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.md +++ b/packages/docs/src/routes/api/qwik-city-middleware-request-handler/index.md @@ -258,24 +258,24 @@ export interface RequestEventAction extends Request export interface RequestEventBase ``` -| Property | Modifiers | Type | Description | -| ----------------- | --------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [basePathname](#) | readonly | string | The base pathname of the request, which can be configured at build time. Defaults to /. | -| [cacheControl](#) | readonly | (cacheControl: [CacheControl](#cachecontrol)) => void |

Convenience method to set the Cache-Control header.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control

| -| [clientConn](#) | readonly | [ClientConn](#clientconn) | Provides information about the client connection, such as the IP address and the country the request originated from. | -| [cookie](#) | readonly | [Cookie](#cookie) |

HTTP request and response cookie. Use the get() method to retrieve a request cookie value. Use the set() method to set a response cookie value.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies

| -| [env](#) | readonly | [EnvGetter](#envgetter) | Platform provided environment variables. | -| [headers](#) | readonly | Headers |

HTTP response headers. Notice it will be empty until you first add a header. If you want to read the request headers, use request.headers instead.

https://developer.mozilla.org/en-US/docs/Glossary/Response\_header

| -| [method](#) | readonly | string |

HTTP request method.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods

| -| [params](#) | readonly | Readonly<Record<string, string>> | URL path params which have been parsed from the current url pathname segments. Use query to instead retrieve the query string search params. | -| [parseBody](#) | readonly | () => Promise<unknown> |

This method will check the request headers for a Content-Type header and parse the body accordingly. It supports application/json, application/x-www-form-urlencoded, and multipart/form-data content types.

If the Content-Type header is not set, it will return null.

| -| [pathname](#) | readonly | string |

URL pathname. Does not include the protocol, domain, query string (search params) or hash.

https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname

| -| [platform](#) | readonly | PLATFORM | Platform specific data and functions | -| [query](#) | readonly | URLSearchParams |

URL Query Strings (URL Search Params). Use params to instead retrieve the route params found in the url pathname.

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

| -| [request](#) | readonly | Request | HTTP request information. | -| [sharedMap](#) | readonly | Map<string, any> | Shared Map across all the request handlers. Every HTTP request will get a new instance of the shared map. The shared map is useful for sharing data between request handlers. | -| [signal](#) | readonly | AbortSignal | Request's AbortSignal (same as request.signal). This signal indicates that the request has been aborted. | -| [url](#) | readonly | URL | HTTP request URL. | +| Property | Modifiers | Type | Description | +| ----------------- | --------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [basePathname](#) | readonly | string | The base pathname of the request, which can be configured at build time. Defaults to /. | +| [cacheControl](#) | readonly | (cacheControl: [CacheControl](#cachecontrol), target?: CacheControlTarget) => void |

Convenience method to set the Cache-Control header. Depending on your CDN, you may want to add another cacheControl with the second argument set to CDN-Cache-Control or any other value (we provide the most common values for auto-complete, but you can use any string you want).

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control and https://qwik.builder.io/docs/caching/\#CDN-Cache-Controls for more information.

| +| [clientConn](#) | readonly | [ClientConn](#clientconn) | Provides information about the client connection, such as the IP address and the country the request originated from. | +| [cookie](#) | readonly | [Cookie](#cookie) |

HTTP request and response cookie. Use the get() method to retrieve a request cookie value. Use the set() method to set a response cookie value.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies

| +| [env](#) | readonly | [EnvGetter](#envgetter) | Platform provided environment variables. | +| [headers](#) | readonly | Headers |

HTTP response headers. Notice it will be empty until you first add a header. If you want to read the request headers, use request.headers instead.

https://developer.mozilla.org/en-US/docs/Glossary/Response\_header

| +| [method](#) | readonly | string |

HTTP request method.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods

| +| [params](#) | readonly | Readonly<Record<string, string>> | URL path params which have been parsed from the current url pathname segments. Use query to instead retrieve the query string search params. | +| [parseBody](#) | readonly | () => Promise<unknown> |

This method will check the request headers for a Content-Type header and parse the body accordingly. It supports application/json, application/x-www-form-urlencoded, and multipart/form-data content types.

If the Content-Type header is not set, it will return null.

| +| [pathname](#) | readonly | string |

URL pathname. Does not include the protocol, domain, query string (search params) or hash.

https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname

| +| [platform](#) | readonly | PLATFORM | Platform specific data and functions | +| [query](#) | readonly | URLSearchParams |

URL Query Strings (URL Search Params). Use params to instead retrieve the route params found in the url pathname.

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

| +| [request](#) | readonly | Request | HTTP request information. | +| [sharedMap](#) | readonly | Map<string, any> | Shared Map across all the request handlers. Every HTTP request will get a new instance of the shared map. The shared map is useful for sharing data between request handlers. | +| [signal](#) | readonly | AbortSignal | Request's AbortSignal (same as request.signal). This signal indicates that the request has been aborted. | +| [url](#) | readonly | URL | HTTP request URL. | [Edit this section](https://github.com/BuilderIO/qwik/tree/main/packages/qwik-city/middleware/request-handler/types.ts) diff --git a/packages/docs/src/routes/docs/(qwikcity)/caching/index.mdx b/packages/docs/src/routes/docs/(qwikcity)/caching/index.mdx index e54ee20f026..6ede56dd3fb 100644 --- a/packages/docs/src/routes/docs/(qwikcity)/caching/index.mdx +++ b/packages/docs/src/routes/docs/(qwikcity)/caching/index.mdx @@ -3,6 +3,7 @@ title: Caching | QwikCity contributors: - steve8708 - harishkrishnan24 + - maiieul --- # Caching Responses @@ -95,3 +96,41 @@ export const onGet: RequestHandler = async ({ cacheControl, url }) => { } }; ``` + +## CDN Cache Controls + +For even more control on your caching strategy, your CDN might have another layer of cache control headers. + +The `cacheControl` convenience method can receive a second argument (set to `"Cache-Control"` by default). You can pass in any string value specific to your CDN such as "CDN-Cache-Control", "Cloudflare-CDN-Cache-Control", "Vercel-CDN-Cache-Control", etc. + +```tsx +cacheControl({ + maxAge: 5, + staleWhileRevalidate: 60 * 60 * 24 * 365, +}, "CDN-Cache-Control"); +``` + +### Missing controls + +Some CDNs (such as Vercel Edge) may strip some of your "Cache-Control" headers. + +[On Vercel's documentation:](https://vercel.com/docs/edge-network/caching#cdn-cache-control) +> If you set Cache-Control without a CDN-Cache-Control, the Vercel Edge Network strips s-maxage and stale-while-revalidate from the response before sending it to the browser. To determine if the response was served from the cache, check the [x-vercel-cache](https://vercel.com/docs/edge-network/caching#x-vercel-cache) header in the response. + +So if your CDN strips some cache control headers away by default (like Vercel Edge) and you want the browser to use "stale-while-revalidate" or "s-maxage", you can add another `cacheControl`: + +```tsx title="src/routes/layout.tsx" +import type { RequestHandler } from "@builder.io/qwik-city"; + +export const onGet: RequestHandler = async ({ cacheControl }) => { + // If you want the browser to use "stale-while-revalidate" or "s-maxage" Cache Control headers, you have to add the second cacheControl with "CDN-Cache-Control" or "Vercel-CDN-Cache-Control" on Vercel Edge + cacheControl({ + staleWhileRevalidate: 60 * 60 * 24 * 365, + maxAge: 5, + }); + cacheControl({ + maxAge: 5, + staleWhileRevalidate: 60 * 60 * 24 * 365, + }, "CDN-Cache-Control"); +}; +``` \ No newline at end of file diff --git a/packages/qwik-city/middleware/request-handler/api.md b/packages/qwik-city/middleware/request-handler/api.md index 350e546c45e..3fca27c6016 100644 --- a/packages/qwik-city/middleware/request-handler/api.md +++ b/packages/qwik-city/middleware/request-handler/api.md @@ -104,7 +104,8 @@ export interface RequestEventAction extends Request // @public (undocumented) export interface RequestEventBase { readonly basePathname: string; - readonly cacheControl: (cacheControl: CacheControl) => void; + // Warning: (ae-forgotten-export) The symbol "CacheControlTarget" needs to be exported by the entry point index.d.ts + readonly cacheControl: (cacheControl: CacheControl, target?: CacheControlTarget) => void; readonly clientConn: ClientConn; readonly cookie: Cookie; readonly env: EnvGetter; diff --git a/packages/qwik-city/middleware/request-handler/request-event.ts b/packages/qwik-city/middleware/request-handler/request-event.ts index 34432ad319e..d8330d855d1 100644 --- a/packages/qwik-city/middleware/request-handler/request-event.ts +++ b/packages/qwik-city/middleware/request-handler/request-event.ts @@ -7,6 +7,8 @@ import type { RequestEventCommon, ResolveValue, QwikSerializer, + CacheControlTarget, + CacheControl, } from './types'; import type { ActionInternal, @@ -151,9 +153,9 @@ export function createRequestEvent( exit, - cacheControl: (cacheControl) => { + cacheControl: (cacheControl: CacheControl, target: CacheControlTarget = 'Cache-Control') => { check(); - headers.set('Cache-Control', createCacheControl(cacheControl)); + headers.set(target, createCacheControl(cacheControl)); }, resolveValue: (async (loaderOrAction: LoaderInternal | ActionInternal) => { diff --git a/packages/qwik-city/middleware/request-handler/types.ts b/packages/qwik-city/middleware/request-handler/types.ts index f7803795160..9f8e44bd9e3 100644 --- a/packages/qwik-city/middleware/request-handler/types.ts +++ b/packages/qwik-city/middleware/request-handler/types.ts @@ -344,11 +344,11 @@ export interface RequestEventBase { readonly parseBody: () => Promise; /** - * Convenience method to set the Cache-Control header. + * Convenience method to set the Cache-Control header. Depending on your CDN, you may want to add another cacheControl with the second argument set to `CDN-Cache-Control` or any other value (we provide the most common values for auto-complete, but you can use any string you want). * - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control and https://qwik.builder.io/docs/caching/#CDN-Cache-Controls for more information. */ - readonly cacheControl: (cacheControl: CacheControl) => void; + readonly cacheControl: (cacheControl: CacheControl, target?: CacheControlTarget) => void; /** * Provides information about the client connection, such as the IP address and the country the request originated from. @@ -431,6 +431,17 @@ export interface CacheControlOptions { immutable?: boolean; } +/** + * @public + */ +export type CacheControlTarget = + | 'Cache-Control' + | 'CDN-Cache-Control' + | 'Cloudflare-CDN-Cache-Control' + | 'Vercel-CDN-Cache-Control' + | '~ANY-OTHER-STRING' + | (string & {}); + /** * @public */