react-native中使用SockJs和StompJs

本文梳理在使用过程中遇到的坑点(Android)

开始使用

package.json

{
"name": "websocketDemo",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"react": "16.3.0-alpha.1",
"react-native": "0.54.2",
"sockjs-client": "1.1.4",
"stompjs": "^2.3.3"
},
"devDependencies": {
"babel-jest": "23.0.0-alpha.0",
"babel-preset-react-native": "4.0.0",
"jest": "22.4.2",
"react-test-renderer": "16.3.0-alpha.1"
},
"jest": {
"preset": "react-native"
}
}

然后在App.js中使用

//引入SockJs和 Stompjs
import SockJs from 'sockjs-client'
import {Stomp} from 'stompjs/lib/stomp'
//此处省略
var host = '';//ws服务器ip:port
var endpoint = '';//提供ws服务的端点名称
var socket = new SockJs(`${host}/${endpoint}`);
var stompClient = Stomp.over(socket);
//此处继续省略
//然后你满心欢喜的去连接
stompClient.connect('guest', 'guest', (frame) => {
console.log('frame',frame);
//TOOD 处理的逻辑eg.subscribe topic
}

产生问题

然后在android设备中调试 react-native run-android
不出意外启动你的App后你会看到以下场景
ERROR

**根据出错信息推断,应该是js的参数映射到java方法的形参上出现了类型转换错误 **

接着跟着App提示的信息调试代码

从图中我们可以看出,该方法的参数列表应该使我们实例化SockJs传入的url

再观察图中的traceName 映射到ReactNative Networking模块中的sendRequet方法

查看NetworkingModule(该模块实现了js中的XMLHttpRequest接口)源码发现,最后一个参数的类型为boolean

@ReactMethod
/**
* @param timeout value of 0 results in no timeout
*/
public void sendRequest(
String method,
String url,
final int requestId,
ReadableArray headers,
ReadableMap data,
final String responseType,
final boolean useIncrementalUpdates,
int timeout,
boolean withCredentials)

然而我们实际参数为
["GET","http://192.168.0.101:8080/wechat-custom-msg/info?t=1521610071602",1,[],{"trackingName":"unknown"},"text",true,0,"true"]

很明显最后一个参数是一个字符串,所以导致了解析参数时


出现的java.lang.String cannot be cast to java.lang.Boolean

可以推断是SockJs发起了XHR请求导致App出现了这个问题
最后找到SockJs中的abstract-xhr.js源码

if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) {
debug('withCredentials');
// Mozilla docs says https://developer.mozilla.org/en/XMLHttpRequest :
// "This never affects same-site requests."

this.xhr.withCredentials = 'true';
}

很明显问题就出在这儿。
查看mozilla官网中对XMLHttpRequest的[API][b409798c]描述

The XMLHttpRequest.withCredentials property is a Boolean that indicates whether or not cross-site Access-Control requests should be made using credentials such as cookies, authorization headers or TLS client certificates. Setting withCredentials has no effect on same-site requests.

如何解决

this.xhr.withCredentials = true;
  1. "true"改为Boolean类型的true
  2. 或者到你的项目路径/node_modules/sockjs-client 目录中使用gulp重新编译
    找到sockjs
    [b409798c]: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials “API”