我刚开始使用react-native 以及javascript 中的
fetch
api。我使用后端对我的应用程序进行身份验证,在我的 ios 模拟器中进行几次刷新后,应用程序会检查它是否在初始加载时通过后端进行了身份验证,令我惊讶的是,确实如此!这就引出了一个问题:react-native 和 fetch
api 中持续存在的位置和内容是什么?
fetch
是在本机级 API 之上实现的,并且与 whatwg 规范和众所周知的 github polyfill 略有不同。这意味着当发出实际的 HTTP 请求时,它是由 iOS 上的本机网络堆栈或 Android 上的OkHttp3 发出的,并且在每种情况下,都是由底层 ObjC 或 Java 代码处理和存储 cookie,远离 JS代码。
直到 2015 年 11 月的此提交,cookie 根本无法在 Android 上正确保留,但自 RN 0.16 以来,无论您的 credential
调用中的
fetch
设置如何,它们都在两个平台上都受支持。因此,会话 cookie 等可以开箱即用,如果您不希望保留任何内容,这可能会令人不安。如果您需要从 JS 操作 cookie,请查看react-native-cookies,它与底层 cookie 存储交互。
credentials: "omit"
来阻止 RN 进行糟糕的内置处理并自行完成。请注意,cookie 本质上是附加的(多个
Set-Cookie
标头应添加到该域的 cookie 中):
import setCookieParser from 'set-cookie-parser'
const origFetch = globalThis.fetch
const cookieMap = new Map<string, string>()
function parseCookieString(cookieString: string): Record<string, string> {
return cookieString.split('; ').reduce(
(acc, cookie) => {
const [name, ...rest] = cookie.split('=')
acc[name] = rest.join('=')
return acc
},
{} as Record<string, string>,
)
}
function buildCookieString(cookies: Record<string, string>): string {
return Object.entries(cookies)
.map(([name, value]) => `${name}=${value}`)
.join('; ')
}
// A wrapper around fetch since RN messes up handling of cookies
export function fetch(input: RequestInfo | URL, init?: RequestInit | undefined) {
const hostname = new URL(input instanceof Request ? input.url : input).hostname
return origFetch(input, {
...init,
headers: {
...(init?.headers || {}),
Cookie: cookieMap.get(hostname) || '',
},
credentials: 'omit', // Omit cookies and handle ourselves
}).then(res => {
const existingCookies = cookieMap.get(hostname) || ''
const existingCookiesObj = parseCookieString(existingCookies)
const newCookies = setCookieParser.parse(res.headers.get('Set-Cookie') || '', {
map: true, // Use map to get an object with cookie names as keys
})
// Update the existing cookies with new ones
for (const [name, cookie] of Object.entries(newCookies)) {
existingCookiesObj[name] = cookie.value
}
cookieMap.set(hostname, buildCookieString(existingCookiesObj))
return res
})
}
您可以导入并使用它,或者覆盖 fetch (global.fetch = fetch
)