React Native使用fetch发送http登陆验证请求失败:无法读取set-cookie头并显示network request failed
最近某个应用需要通过调用远程网站的登陆接口,登陆后调用其它API获取用户注册信息。
中间遇到两个坑。
Fetch不允许访问 Set-Cookie 这个 header
React Native 的网络层(基于 RCTNetworking 或底层的 OkHttp、NSURLSession 等)默认不暴露 Set-Cookie 给 JavaScript 层。这是出于安全考虑。对于原生Android应用也通常有同样的限制。
此时可在fetch或 XmlHttpRequest 中配置 credentials: 'include', 允许附加Cookie等信息。此时 react-native 会自动将服务器端写入的session类cookie回传给服务器。react-native只需要完成登陆过程即可。
也可以使用类似json web token的方法,将 sessionid 在服务器端放到响应json中。 如返回:
{
jwt: {
token: 'TOEKN_STRING'
}
}
这样对web服务的改动非常小。后端不需要改变原有的 session 权限管理策略,如 redis 存储等。
const res = await fetch(url, {
method: 'GET',
headers: {
'Cookie': 'sessionid=' + token
},
credentials: 'include'
})
第二种方法就是采用jwt标准,在后续请求加上 authorization: Bearn TOEKN_STRING 这样的 header。
然后修改网站的权限验证机制,添加一个以 authorization 鉴权的中间件。这样的改动会略复杂一些。
Fetch不允许访问http请求
我们调试的请求类似 http://192.168.0.101/api/user/login
在虚拟机中是可以调用正常的,但在手机上测试,会一直显示 network request failed 异常。
从 Android 9(API 级别 28)开始,默认情况下,Android 应用是不允许使用明文网络流量的。这意味着,如果你的应用尝试通过 HTTP 而非 HTTPS 发送或接收数据,应用将会失败。
相关讨论如下:
https://github.com/facebook/react-native/issues/24627 https://github.com/facebook/react-native/issues/32931
我们可以配置 release 的 AndroidManifest.xml 允许明文流量: android:usesCleartextTraffic="true" 即可
AwesomeProject\android\app\src\main\AndroidManifest.xml
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
android:supportsRtl="true">
<activity