FAQ
这里集中了一些从 QRN 转换为 QRN-Web 时比较常见的问题,并有相应的解决方案,如果还无法解决请联系 xinben.zhu。
各种 AJAX 网络错误,比如控制台的 Network Error
QRN 是没有跨域限制的,但是出于安全原因,浏览器限制脚本从跨域服务器获得资源,无法通过脚本跨域取得其他域名下的资源(静态资源除外,通过 script
、img
等标签加载的跨域静态资源是可以访问的),跨域的条件如下:
- 协议不同。从
http://foo.bar
请求https://foo.bar
的资源是跨域的。 - 端口不同。从
http://foo.bar:80
请求http://foo.bar:8080
的资源是跨域的。 - 域名不同。从
http://foo.bar
请求http://static.foo.bar
的资源是跨域的。
注意上述加粗的部分,浏览器不一定是限制脚本发起跨域请求,请求可能正常发送到了服务器并且也获得了响应,但是由于安全原因浏览器会拦截掉服务器的响应而直接给脚本返回一个错误。
既然浏览器知道这是一个跨域请求为什么不直接拦截请求而是拦截响应呢?
因为 CORS 允许简单请求直接向跨域服务器发起而不需要通过 CORS 预检请求。浏览器通过判断响应中的 Access-Control-Allow-Origin
头部来决定是否拦截这个响应,如果响应中没有 Access-Control-Allow-Origin
头部或者有这个头部但是当前域名不在允许范围内,就会拦截这个请求并给发起请求的脚本返回一个 Network Error
错误。
所以这就是为什么有时候明明可以在控制台的 Network 面板中看到请求已经成功发起且响应但是脚本还是报错的原因了。
为了解决这个问题,你需要通过某些方式来绕过跨域限制。解决方案大概有以下几种:
- 使用 CORS。在被请求的服务器上设置相应的 CORS 响应头,一般来说,需要设置以下几个响应头
Access-Control-Allow-Origin
,该响应头设置可以发起跨域请求的域,比如http://foo.bar
。⚠️ 注意,对于不需要凭证的请求,服务器可以将该响应头设置为通配符*
,表示所有域都可以向该站点发起跨域请求。Access-Control-Allow-Methods
,该响应头设置可以用于发起跨域请求的方法,比如POST, GET
表示允许发送使用POST
和GET
方法的请求。Access-Control-Allow-Credentials
,该响应头设置了如果请求的withCredentials
设置为true
时该响应是否应该返回给脚本。即,如果请求中带有身份凭证信息,如果响应中该字段为true
,那么该响应会返回给脚本,但是如果没有该响应头,则该响应会被浏览器拦截。
- 使用反向代理服务器。将 QRN-Web 项目和需要被请求的服务器通过一个反向代理服务器组合起来,以避免跨域问题。比如 QRN-Web 项目的域名为
http://foo.bar
,而 API 的域名为http://api.foo.bar
,那么可以通过 nginx 的反向代理将http://foo.bar/api
映射到http://api.foo.bar
上,项目内请求http://foo.bar/api
就等于请求http://api.foo.bar
,避免了跨域问题。 - 使用 JSONP。JSONP 需要服务器提供支持。
- 使用
websocket
。websocket
没有跨域限制。
Image 图片显示不正确
由于浏览器限制,Image
的 capInsets
属性无法实现,使用该属性会导致背景图片显示和 QRN 上的不一致。
页面为空白
请确认代码中是否有根据平台返回不同页面的逻辑,比如:
if (DeviceInfo.isIOS) {
return <IOS />
} else if (DeviceInfo.isAdr) {
return <Adr />
}
在 QRN-Web 中,DeviceInfo.isIOS
和 (DeviceInfo.isAdr)
返回都是 false
,请使用 (DeviceInfo.isWeb)
来判断。或者可以写成:
if (DeviceInfo.isIOS || DeviceInfo.isIOS) {
return <IOS />
} else if (DeviceInfo.isAdr) {
return <Adr />
}