我要在回家的路上发布此消息,因此请原谅缺少代码,但是我会尽量详细,并在今晚可以添加代码。所以本质上我有一个使用redux和axios的React Native应用程序。简短回顾(请遵循以下代码)可能会说明我做错了事。
Serviceapi.js 创建和导出具有基本URL的基本axios。
const ServiceApi = axios.create({
baseURL: BASE_URL,
responseType: 'json'
});
AuthReducer.js 在登录时,使用post方法手动设置Authorization标头。这在android和ios上均有效,返回登录名,我使用授权标头。
return {
type: PERFORM_LOGIN,
payload: {
user: {
name: username
},
request: {
url: '/login',
method: 'post',
headers: {
'Authorization': 'Basic ' + basicAuth
}
}
}
登录时,我返回以下redux-axios操作,您可以看到我设置了标头:手动授权,效果很好。
// On login success, set the authInterceptor responsible for adding headers
authInterceptor = ServiceApi.interceptors.request.use((config) => {
console.log(`Attaching Authorization to header ${basicAuth}`);
config.headers.common.Authorization = basicAuth;
return config;
}, (error) => {
Promise.reject(error);
});
注销后,我清除了拦截器。我选择在登录和注销时添加和删除,而不是仅仅因为它而一直存在。这可能是个问题,但对于Android来说很好
// Clear the auth interceptor
ServiceApi.interceptors.request.eject(authInterceptor);
同样,这一切在Android上都能正常运行。它看起来正在ios上运行。当我调试拦截器时,它会被调用并设置标头。
但是我在ios上得到了403。详细查看请求后,请求中的android标头与请求中的ios标头之间存在很大差异。请求对象的其余部分相同,但ios和android之间只有_header对象不同。
Android请求
_headers:
accept: "application/json, text/plain, */*"
authorization: "Basic <correct base64 value>"
content-type: "application/json;charset=utf-8"
__proto__: Object
IOS请求
_headers:
accept: (...)
authorization: (...)
content-type: (...)
get accept: ƒ ()
set accept: ƒ ()
get authorization: ƒ ()
set authorization: ƒ ()
get content-type: ƒ ()
set content-type: ƒ ()
__proto__: Object
由于存在差异,因此在查看error.request._headers.authorization;
的控制台时设置了一个断点,我得到的内容与Android标头中包含的内容相同。
index.php 后端服务是一个执行$ _SERVER ['PHP_AUTH_USER']的php文件,如果未设置,则会失败403,这是发生了什么事。我没有访问php的权限,只是被告知这是它的用途。
我再次为未提供代码表示歉意,但等到以后有机会我会再说。也许我需要为ios设置其他功能吗?或者也许ios的php需要额外的标题?
要遵循的代码。
EDIT (更新),更新了代码,希望我没有留下任何编码的登录信息。
编辑2 经过进一步调查,这似乎与apache / PHP有关,而不是react-native / axios。我把一个快递服务器放在一起,它模拟与PHP相同的检查: -寻找授权标头 -打印 -根据此数据返回403或200 w /
在模拟器上使用完全相同的应用程序指向http://localhost:3000运行时,我得到了我期望的结果。除此之外,当我在模拟器上时,我实际上无法登录到实时URL(即使我可以在常规设备上登录),我也遇到了403错误,但是这次稍早了。
编辑3
要提供来自服务器的更多信息,这是我已经能够记录的三个请求:
1)这是来自IOS Emulator iPhone8针对快速服务器的情况:
accept:"application/json, text/plain, */*"
accept-encoding:"gzip, deflate"
accept-language:"en-us"
authorization:"Basic <base 64 encoding>"
connection:"keep-alive"
content-length:"0"
host:"localhost:3000"
user-agent:"MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.
2)这是从同一模拟器到apache / PHP(5.3.3),我们可以看到没有Authorization标头。
Accept: application/json, text/plain, */*
User-Agent: MobileApp/1 CFNetwork/978.0.7 Darwin/18.5.0
Accept-Language: en-us
Accept-Encoding: br, gzip, deflate
Connection: keep-alive
3)这是从Android到apache / PHP(5.3.3):
authorization: Basic <Base 64 encoding>
Host: api.serviceurl.com
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.12.1
编辑4 因此,经过一段时间的搜索和谷歌搜索,事实证明问题出在Zend Framework和fastcgi上,它们会自动删除Authorization标头。奇怪的是,它仅是通过IOS而不是Android来完成的,这真的没有道理。
我们在日志中注意到的事情是,它接受Android和Postman作为POST,但是将IOS请求记录为GET。我不确定这到底是怎么回事,但这似乎又是另一回事。我已经更新了任务,将zend作为标签。有很多关于用ReWriteMod在apache / zend上解决此问题的SO文章,所以我先介绍一下,看看它是否可以解决问题。
**编辑5 ** 到目前为止,我们已经尝试遵循SO文章,该文章要求添加以下内容(Authorization header missing in django rest_framework, is apache to blame?):
SetEnvIfNoCase Authorization ^(.*) -e=PHP_HTTP_AUTH
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
结果如下:
// IOS
_SERVER[PHP_HTTP_AUTH] = <blank>
_SERVER[HTTP_AUTHORIZATION] = <blank>
// Android
_SERVER[PHP_HTTP_AUTH] = Username
_SERVER[HTTP_AUTHORIZATION] = Basic <Base65 encoded>
_SERVER[PHP_HTTP_PW] = Password
所以我们知道Header Authorization正在进入Apache,但是现在它成为空白。我正在研究其他一些SO答案,但搜索仍在继续...
编辑6
已解决(ish)
答案 0 :(得分:2)
结果是,对于IOS的请求,它是必需的斜杠。我可以找到此问题描述为的链接https://github.com/square/retrofit/issues/1037:
对于那些感兴趣的人:我们使用Django作为后端,默认情况下, 不在端点上提供尾部斜杠Django从非斜杠重定向 端点到斜杠端点。
现在,我们不使用Django,但显然我们的Zend配置是 同样的问题-Android能够重定向而没有问题,而IOS却没有。关于任务的另一条评论指出:
当跨主机(连接)重定向时,OkHttp剥离“ Authorization”标头 通过原始主机的3xx响应。
这似乎不太准确,因为Android使用的是OkHttp,并且工作正常。看来使用达尔文的IOS遇到了问题。
编辑
我从最初的帖子中忘记了其他内容,我还不得不将拦截器从config.headers.common.Authorization = ...
行更改为config.headers.Authorization = ...
,出于某种原因,它保留了原意。原始方式将授权转换为授权,而后者将其保留为授权。不知道这是否是一个问题,但是我还是做到了。
// On login success, set the authInterceptor responsible for adding headers
authInterceptor = ServiceApi.interceptors.request.use((config) => {
console.log(`Attaching Authorization to header ${basicAuth}`);
config.headers.Authorization = basicAuth;
return config;
}, (error) => {
Promise.reject(error);
});