Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: improve docs around geolocation and IP headers #59719

Merged
merged 5 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,28 @@ export function middleware(request) {
}
```

### `waitUntil` and `NextFetchEvent`

The `NextFetchEvent` object extends the native [`FetchEvent`](https://developer.mozilla.org/docs/Web/API/FetchEvent) object, and includes the [`waitUntil()`](https://developer.mozilla.org/docs/Web/API/ExtendableEvent/waitUntil) method.

The `waitUntil()` method takes a promise as an argument, and extends the lifetime of the Middleware until the promise settles. This is useful for performing work in the background.

```typescript
leerob marked this conversation as resolved.
Show resolved Hide resolved
import { NextResponse } from 'next/server'
import type { NextFetchEvent, NextRequest } from 'next/server'

export function middleware(req: NextRequest, event: NextFetchEvent) {
event.waitUntil(
fetch('https://my-analytics-platform.com', {
method: 'POST',
body: JSON.stringify({ pathname: req.nextUrl.pathname }),
})
)

return NextResponse.next()
}
```

## Advanced Middleware Flags

In `v13.1` of Next.js two additional flags were introduced for middleware, `skipMiddlewareUrlNormalize` and `skipTrailingSlashRedirect` to handle advanced use cases.
Expand Down
57 changes: 48 additions & 9 deletions docs/02-app/02-api-reference/04-functions/headers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,63 @@ const headersList = headers()
`headers()` can be used in combination with [Suspense for Data Fetching](/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating).

```jsx filename="app/page.js"
import { Suspense } from 'react'
import { headers } from 'next/headers'

async function getUser() {
const headersInstance = headers()
const authorization = headersInstance.get('authorization')
// Forward the authorization header
async function User() {
const authorization = headers().get('authorization')
const res = await fetch('...', {
headers: { authorization },
headers: { authorization }, // Forward the authorization header
})
return res.json()
}
const user = await res.json()

export default async function UserPage() {
const user = await getUser()
return <h1>{user.name}</h1>
}

export default function Page() {
return (
<Suspense fallback={null}>
<User />
</Suspense>
)
}
```

#### IP Address

`headers()` can be used to get the IP address of the client.

```jsx filename="app/page.js"
import { Suspense } from 'react'
import { headers } from 'next/headers'

function IP() {
const FALLBACK_IP_ADDRESS = '0.0.0.0'
const forwardedFor = headers().get('x-forwarded-for')

if (forwardedFor) {
return forwardedFor.split(',')[0] ?? FALLBACK_IP_ADDRESS
}

return headers().get('x-real-ip') ?? FALLBACK_IP_ADDRESS
}

export default function Page() {
return (
<Suspense fallback={null}>
<IP />
</Suspense>
)
}
```

In addition to `x-forwarded-for`, `headers()` can also read:

- `x-real-ip`
- `x-forwarded-host`
- `x-forwarded-port`
- `x-forwarded-proto`

## Version History

| Version | Changes |
Expand Down
69 changes: 69 additions & 0 deletions docs/02-app/02-api-reference/04-functions/next-request.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: NextRequest
description: API Reference for NextRequest.
---

{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}

NextRequest extends the [Web Request API](https://developer.mozilla.org/docs/Web/API/Request) with additional convenience methods.

## `cookies`
Expand Down Expand Up @@ -82,6 +84,73 @@ request.nextUrl.pathname
request.nextUrl.searchParams
```

The following options are available:

<PagesOnly>

| Property | Type | Description |
| ----------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `basePath` | `string` | The [base path](/docs/pages/api-reference/next-config-js/basePath) of the URL. |
| `buildId` | `string` \| `undefined` | The build identifier of the Next.js application. Can be [customized](/docs/pages/api-reference/next-config-js/generateBuildId). |
| `defaultLocale` | `string` \| `undefined` | The default locale for [internationalization](/docs/pages/building-your-application/routing/internationalization). |
| `domainLocale` | | |
| - `defaultLocale` | `string` | The default locale within a domain. |
| - `domain` | `string` | The domain associated with a specific locale. |
| - `http` | `boolean` \| `undefined` | Indicates if the domain is using HTTP. |
| `locales` | `string[]` \| `undefined` | An array of available locales. |
| `locale` | `string` \| `undefined` | The currently active locale. |
| `url` | `URL` | The URL object. |

</PagesOnly>

<AppOnly>

| Property | Type | Description |
| -------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `basePath` | `string` | The [base path](/docs/app/api-reference/next-config-js/basePath) of the URL. |
| `buildId` | `string` \| `undefined` | The build identifier of the Next.js application. Can be [customized](/docs/app/api-reference/next-config-js/generateBuildId). |
| `url` | `URL` | The URL object. |
| `pathname` | `string` | The pathname of the URL. |
| `searchParams` | `Object` | The search parameters of the URL. |

> **Note:** The internationalization properties from the Pages Router and not added for usage in the App Router. Learn more about [internationalization with the App Router](/docs/app/building-your-application/routing/internationalization).
leerob marked this conversation as resolved.
Show resolved Hide resolved

</AppOnly>

## `ip`

The `ip` property is a string that contains the IP address of the request. This value can optionally be provided by your hosting platform.

On [Vercel](https://vercel.com/docs/frameworks/nextjs?utm_source=next-site&utm_medium=docs&utm_campaign=next-website), this value is provided by default. On other platforms, you can use the [`X-Forwarded-For`](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-For) header to provide the IP address.
leerob marked this conversation as resolved.
Show resolved Hide resolved

```ts
// Provided by Vercel
request.ip
// Self-hosting
request.headers.get('X-Forwarded-For')
```

## `geo`

The `geo` property is an object that contains the geographic information of the request. This value can optionally be provided by your hosting platform.

On [Vercel](https://vercel.com/docs/frameworks/nextjs?utm_source=next-site&utm_medium=docs&utm_campaign=next-website), this value is provided by default. On other platforms, you can use the [`X-Forwarded-For`](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-Forwarded-For) header to provide the IP address, then use a [third-party service](https://ip-api.com/) to lookup the geographic information.
leerob marked this conversation as resolved.
Show resolved Hide resolved

```ts
// Provided by Vercel
request.geo.city
request.geo.country
request.geo.region
request.geo.latitude
request.geo.longitude

// Self-hosting
function getGeo(request) {
let ip = request.headers.get('X-Forwarded-For')
// Use a third-party service to lookup the geographic information
}
```

## Version History

| Version | Changes |
Expand Down
2 changes: 2 additions & 0 deletions docs/02-app/02-api-reference/04-functions/next-response.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: NextResponse
description: API Reference for NextResponse.
---

{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}

NextResponse extends the [Web Response API](https://developer.mozilla.org/docs/Web/API/Response) with additional convenience methods.

## `cookies`
Expand Down
21 changes: 21 additions & 0 deletions docs/02-app/02-api-reference/04-functions/redirect.mdx
leerob marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ export default async function Profile({ params }) {

> **Good to know**: `redirect` does not require you to use `return redirect()` as it uses the TypeScript [`never`](https://www.typescriptlang.org/docs/handbook/2/functions.html#never) type.

## FAQ

### Why does `redirect` use 307 and 308?

When using `redirect()` you may notice that the status codes used are `307` for a temporary redirect, and `308` for a permanent redirect. While traditionally a `302` was used for a temporary redirect, and a `301` for a permanent redirect, many browsers changed the request method of the redirect, from a `POST` to `GET` request when using a `302`, regardless of the origins request method.

Taking the following example of a redirect from `/users` to `/people`, if you make a `POST` request to `/users` to create a new user, and are conforming to a `302` temporary redirect, the request method will be changed from a `POST` to a `GET` request. This doesn't make sense, as to create a new user, you should be making a `POST` request to `/people`, and not a `GET` request.

The introduction of the `307` status code means that the request method is preserved as `POST`.

- `302` - Temporary redirect, will change the request method from `POST` to `GET`
- `307` - Temporary redirect, will preserve the request method as `POST`

The `redirect()` method uses a `307` by default, instead of a `302` temporary redirect, meaning your requests will _always_ be preserved as `POST` requests.

If you want to cause a `GET` response to a `POST` request, use `303`.
leerob marked this conversation as resolved.
Show resolved Hide resolved

[Learn more](https://developer.mozilla.org/docs/Web/HTTP/Redirections) about HTTP Redirects.

## Version History

| Version | Changes |
| --------- | ---------------------- |
| `v13.0.0` | `redirect` introduced. |
71 changes: 71 additions & 0 deletions docs/02-app/02-api-reference/04-functions/userAgent.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: userAgent
description: The userAgent helper extends the Web Request API with additional properties and methods to interact with the user agent object from the request.
---

{/* The content of this doc is shared between the app and pages router. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}

The `userAgent` helper extends the [Web Request API](https://developer.mozilla.org/docs/Web/API/Request) with additional properties and methods to interact with the user agent object from the request.
leerob marked this conversation as resolved.
Show resolved Hide resolved

```ts filename="middleware.ts" switcher
import { NextRequest, NextResponse, userAgent } from 'next/server'

export function middleware(request: NextRequest) {
const url = request.nextUrl
const { device } = userAgent(request)
const viewport = device.type === 'mobile' ? 'mobile' : 'desktop'
url.searchParams.set('viewport', viewport)
return NextResponse.rewrite(url)
}
```

```js filename="middleware.js" switcher
import { NextResponse, userAgent } from 'next/server'

export function middleware(request) {
const url = request.nextUrl
const { device } = userAgent(request)
const viewport = device.type === 'mobile' ? 'mobile' : 'desktop'
url.searchParams.set('viewport', viewport)
return NextResponse.rewrite(url)
}
```

## `isBot`

A boolean indicating whether the request comes from a known bot.
leerob marked this conversation as resolved.
Show resolved Hide resolved

## `browser`

An object containing information about the browser used in the request.

- `name`: A string representing the browser's name, or `undefined` if not identifiable.
- `version`: A string representing the browser's version, or `undefined`.

## `device`

An object containing information about the device used in the request.

- `model`: A string representing the model of the device, or `undefined`.
- `type`: A string representing the type of the device, such as `console`, `mobile`, `tablet`, `smarttv`, `wearable`, `embedded`, or `undefined`.
- `vendor`: A string representing the vendor of the device, or `undefined`.

## `engine`

An object containing information about the browser's engine.

- `name`: A string representing the engine's name. Possible values include: `Amaya`, `Blink`, `EdgeHTML`, `Flow`, `Gecko`, `Goanna`, `iCab`, `KHTML`, `Links`, `Lynx`, `NetFront`, `NetSurf`, `Presto`, `Tasman`, `Trident`, `w3m`, `WebKit` or `undefined`.
- `version`: A string representing the engine's version, or `undefined`.

## `os`

An object containing information about the operating system.

- `name`: A string representing the name of the OS, or `undefined`.
- `version`: A string representing the version of the OS, or `undefined`.

## `cpu`

An object containing information about the CPU architecture.

- `architecture`: A string representing the architecture of the CPU. Possible values include: `68k`, `amd64`, `arm`, `arm64`, `armhf`, `avr`, `ia32`, `ia64`, `irix`, `irix64`, `mips`, `mips64`, `pa-risc`, `ppc`, `sparc`, `sparc64` or `undefined`
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ In some rare cases, you might need to assign a custom status code for older HTTP

## Other Redirects

- Inside [API Routes](/docs/pages/api-reference/functions/next-server), you can use `res.redirect()`.
- Inside [API Routes](/docs/pages/building-your-application/routing/api-routes) and [Route Handlers](/docs/app/building-your-application/routing/route-handlers), you can redirect based on the incoming request.
- Inside [`getStaticProps`](/docs/pages/building-your-application/data-fetching/get-static-props) and [`getServerSideProps`](/docs/pages/building-your-application/data-fetching/get-server-side-props), you can redirect specific pages at request-time.

## Version History
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) {
}
```

- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage), plus some [pre-built middlewares](/docs/pages/api-reference/functions/next-server)
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse), plus some [helper functions](/docs/pages/api-reference/functions/next-server)
- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage)
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse)

## HTTP Methods

Expand Down
7 changes: 7 additions & 0 deletions docs/03-pages/02-api-reference/02-functions/next-request.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: NextRequest
description: API Reference for NextRequest.
source: app/api-reference/functions/next-request
---

{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
7 changes: 7 additions & 0 deletions docs/03-pages/02-api-reference/02-functions/next-response.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: NextResponse
description: API Reference for NextResponse.
source: app/api-reference/functions/next-response
---

{/* DO NOT EDIT. The content of this doc is generated from the source above. To edit the content of this page, navigate to the source page in your editor. You can use the `<PagesOnly>Content</PagesOnly>` component to add content that is specific to the Pages Router. Any shared content should not be wrapped in a component. */}
Loading