mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 09:25:54 +00:00
feat(nuxt3, bridge): useReqHeaders
composable (#2173)
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
parent
c824905b99
commit
5ab18162dd
@ -117,6 +117,36 @@ const { data } = await useFetch('/api/count')
|
|||||||
|
|
||||||
This composable behaves identically to `useFetch` with the `lazy: true` option set. In other words, the async function does not block navigation. That means you will need to handle the situation where the data is `null` (or whatever value you have provided in a custom `default` factory function).
|
This composable behaves identically to `useFetch` with the `lazy: true` option set. In other words, the async function does not block navigation. That means you will need to handle the situation where the data is `null` (or whatever value you have provided in a custom `default` factory function).
|
||||||
|
|
||||||
|
## Isomorphic fetch
|
||||||
|
|
||||||
|
When we call `fetch` in the browser, user headers like `cookie` will be directly sent to the API.
|
||||||
|
But during server-side-rendering, since the `fetch` request is originating from the server, it doesn't include the user's browser cookies.
|
||||||
|
|
||||||
|
We can use [`useRequestHeaders`](/docs/usage/ssr) to access and proxy cookies to the API from server-side.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
The example below adds the request headers to an isomorphic `fetch` call to ensure that the API endpoint has access to the same `cookie` header originally sent by the user.
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
const { data } = useFetch('/api/me', {
|
||||||
|
headers: useRequestHeaders(['cookie'])
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
::alert{type="warning"}
|
||||||
|
Be very careful before proxy headers to an external API and include headers that you need.
|
||||||
|
Not all headers are safe to be bypassed and might introduce unwanted behavior.
|
||||||
|
Here is a list of common headers that are NOT to be proxied:
|
||||||
|
|
||||||
|
* `host`, `accept`
|
||||||
|
* `content-length`, `content-md5`, `content-type`
|
||||||
|
* `x-forwarded-host`, `x-forwarded-port`, `x-forwarded-proto`
|
||||||
|
* `cf-connecting-ip`, `cf-ray`
|
||||||
|
::
|
||||||
|
|
||||||
## Best practices
|
## Best practices
|
||||||
|
|
||||||
The data returned by these composables will be stored inside the page payload. This means that every key returned that is not used in your component will be added to the payload.
|
The data returned by these composables will be stored inside the page payload. This means that every key returned that is not used in your component will be added to the payload.
|
||||||
|
19
docs/content/3.docs/1.usage/7.ssr.md
Normal file
19
docs/content/3.docs/1.usage/7.ssr.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# SSR utilities
|
||||||
|
|
||||||
|
Nuxt provides composables and utilities for first-class server-side-rendering support.
|
||||||
|
|
||||||
|
## useRequestHeaders
|
||||||
|
|
||||||
|
Within your pages, components, and plugins you can use `useRequestHeaders` to access the incoming request headers.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Get all request headers
|
||||||
|
const headers = useRequestHeaders()
|
||||||
|
|
||||||
|
// Get only cookie request header
|
||||||
|
const headers = useRequestHeaders(['cookie'])
|
||||||
|
```
|
||||||
|
|
||||||
|
::alert{icon=👉}
|
||||||
|
On client side, `useRequestHeaders` will return an empty object.
|
||||||
|
::
|
@ -9,6 +9,7 @@ import { useNuxtApp } from './app'
|
|||||||
export { useLazyAsyncData } from './asyncData'
|
export { useLazyAsyncData } from './asyncData'
|
||||||
export { useLazyFetch } from './fetch'
|
export { useLazyFetch } from './fetch'
|
||||||
export { useCookie } from './cookie'
|
export { useCookie } from './cookie'
|
||||||
|
export { useRequestHeaders } from './ssr'
|
||||||
|
|
||||||
export * from '@vue/composition-api'
|
export * from '@vue/composition-api'
|
||||||
|
|
||||||
|
1
packages/bridge/src/runtime/ssr.ts
Symbolic link
1
packages/bridge/src/runtime/ssr.ts
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../nuxt3/src/app/composables/ssr.ts
|
@ -4,3 +4,4 @@ export { useHydration } from './hydrate'
|
|||||||
export { useState } from './state'
|
export { useState } from './state'
|
||||||
export { useFetch, useLazyFetch } from './fetch'
|
export { useFetch, useLazyFetch } from './fetch'
|
||||||
export { useCookie } from './cookie'
|
export { useCookie } from './cookie'
|
||||||
|
export { useRequestHeaders } from './ssr'
|
||||||
|
11
packages/nuxt3/src/app/composables/ssr.ts
Normal file
11
packages/nuxt3/src/app/composables/ssr.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* eslint-disable no-redeclare */
|
||||||
|
import { useNuxtApp } from '#app'
|
||||||
|
|
||||||
|
export function useRequestHeaders<K extends string = string> (include: K[]): Record<K, string>;
|
||||||
|
export function useRequestHeaders (): Readonly<Record<string, string>>;
|
||||||
|
export function useRequestHeaders (include?) {
|
||||||
|
if (process.client) { return {} }
|
||||||
|
const headers: Record<string, string> = useNuxtApp().ssrContext?.req.headers ?? {}
|
||||||
|
if (!include) { return headers }
|
||||||
|
return Object.fromEntries(include.map(key => [key, headers[key]]))
|
||||||
|
}
|
@ -14,7 +14,8 @@ export const Nuxt3AutoImports: AutoImportSource[] = [
|
|||||||
'useState',
|
'useState',
|
||||||
'useFetch',
|
'useFetch',
|
||||||
'useLazyFetch',
|
'useLazyFetch',
|
||||||
'useCookie'
|
'useCookie',
|
||||||
|
'useRequestHeaders'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// #meta
|
// #meta
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
import { readFileSync } from 'fs'
|
||||||
import type { AutoImport } from '@nuxt/schema'
|
import type { AutoImport } from '@nuxt/schema'
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
|
import { join } from 'pathe'
|
||||||
|
import { createCommonJS, findExports } from 'mlly'
|
||||||
import * as VueFunctions from 'vue'
|
import * as VueFunctions from 'vue'
|
||||||
import { AutoImportContext, updateAutoImportContext } from '../src/auto-imports/context'
|
import { AutoImportContext, updateAutoImportContext } from '../src/auto-imports/context'
|
||||||
import { TransformPlugin } from '../src/auto-imports/transform'
|
import { TransformPlugin } from '../src/auto-imports/transform'
|
||||||
@ -37,6 +40,27 @@ describe('auto-imports:transform', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const excludedNuxtHelpers = ['useHydration']
|
||||||
|
|
||||||
|
describe('auto-imports:nuxt3', () => {
|
||||||
|
try {
|
||||||
|
const { __dirname } = createCommonJS(import.meta.url)
|
||||||
|
const entrypointContents = readFileSync(join(__dirname, '../src/app/composables/index.ts'), 'utf8')
|
||||||
|
|
||||||
|
const names = findExports(entrypointContents).flatMap(i => i.names || i.name)
|
||||||
|
for (const name of names) {
|
||||||
|
if (excludedNuxtHelpers.includes(name)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
it(`should register ${name} globally`, () => {
|
||||||
|
expect(Nuxt3AutoImports.find(a => a.from === '#app').names).to.include(name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const excludedVueHelpers = [
|
const excludedVueHelpers = [
|
||||||
'EffectScope',
|
'EffectScope',
|
||||||
'ReactiveEffect',
|
'ReactiveEffect',
|
||||||
|
Loading…
Reference in New Issue
Block a user