客户端方法
uri 方法
- client.uri();
该方法返回客户端当前所使用的地址。如果客户端在创建时设置了多个服务地址,该属性的值仅为这多个地址中当前正在使用中的那个地址。
uriList 方法
- client.uriList(value);
- client.uriList();
有参数时为设置 uriList
的值,无参数时返回 uriList
的设置值,该方法的参数和返回值为字符串数组类型。
该方法表示当前客户端可以调用的服务地址列表。
id 方法
- client.id();
该方法返回当前客户端在进行推送订阅时的唯一编号。在没有进行推送订阅或者使用自己指定 id 方式进行推送订阅时,该方法返回值为 null。你也可以调用 client'#';
方法来手动从服务器端获取该 id
的值。
binary 方法
- client.binary(value);
- client.binary();
有参数时为设置 binary
的值,无参数时返回 binary
的设置值,该方法的参数和返回值为 Boolean
类型。默认值为 false
。
该方法表示当前客户端的调用是否允许传输二进制数据。
你也可以针对某个调用进行单独设置。
failswitch 方法
- client.failswitch(value);
- client.failswitch();
有参数时为设置 failswitch
的值,无参数时返回 failswitch
的设置值,该方法的参数和返回值为 Boolean
类型。默认值为 false
。
该方法表示当前客户端在因网络原因调用失败时是否自动切换服务地址。当客户端服务地址仅设置一个时,不管该属性值为何,都不会切换地址。
你也可以针对某个调用进行单独设置。
failround 方法
- client.failround();
该方法默认返回值为 0。当调用中发生服务地址切换时,如果服务列表中所有的服务地址都切换过一遍之后,该方法返回值会加 1。你可以根据该方法的返回值来决定是否更新服务列表。更新服务列表可以使用 uriList
方法。
timeout 方法
- client.timeout(value);
- client.timeout();
有参数时为设置 timeout
的值,无参数时返回 timeout
的设置值,该方法的参数和返回值为整数类型,默认值为 30000
,单位是毫秒(ms)。
该方法表示当前客户端在调用时的超时时间,如果调用超过该时间后仍然没有返回,则会以超时错误返回。
你也可以针对某个调用进行单独设置。
idempotent 方法
- client.idempotent(value);
- client.idempotent();
有参数时为设置 idempotent
的值,无参数时返回 idempotent
的设置值,该方法的参数和返回值为 Boolean
类型,默认值为 false
。
该方法表示调用是否为幂等性调用,幂等性调用表示不论该调用被重复几次,对服务器的影响都是相同的。幂等性调用在因网络原因调用失败时,会自动重试。如果 failswitch
属性同时被设置为 true
,并且客户端设置了多个服务地址,在重试时还会自动切换地址。
你也可以针对某个调用进行单独设置。
retry 方法
- client.retry(value);
- client.retry();
有参数时为设置 retry
的值,无参数时返回 retry
的设置值,该方法的参数和返回值为整数类型,默认值为 10
。
该方法表示幂等性调用在因网络原因调用失败后的重试次数。只有 idempotent
属性为 true
时,该属性才有作用。
你也可以针对某个调用进行单独设置。
byref 方法
- client.byref(value);
- client.byref();
有参数时为设置 byref
的值,无参数时返回 byref
的设置值,该方法的参数和返回值为 Boolean
类型,默认值为 false
。
该方法表示调用是否为引用参数传递。当设置为引用参数传递时,服务器端会传回修改后的参数值(即使没有修改也会传回)。因此,当不需要该功能时,设置为 false
会比较节省流量。
你也可以针对某个调用进行单独设置。
simple 方法
- client.simple(value);
- client.simple();
有参数时为设置 simple
的值,无参数时返回 simple
的设置值,该方法的参数和返回值为 Boolean
类型,默认值为 false
。
该方法表示调用中所传输的数据是否为简单数据。简单数据是指:null、数字(包括整数、长整数、浮点数)、Boolean 值、字符串、二进制数据、日期时间等基本类型的数据或者不包含引用的数组、Map 和对象。当该属性设置为 true
时,在进行序列化操作时,将忽略引用处理,加快序列化速度。但如果数据不是简单类型的情况下,将该属性设置为 true
,可能会因为死循环导致堆栈溢出的错误。
简单的讲,用 JSON
可以表示的数据都是简单数据。但是对于比较复杂的 JSON
数据,设置 simple
为 true
可能不会加快速度,反而会减慢,比如对象数组。因为默认情况下,hprose 会对对象数组中的重复字符串的键值进行引用处理,这种引用处理可以对序列化起到优化作用。而关闭引用处理,也就关闭了这种优化。
你也可以针对某个调用进行单独设置。
因为不同调用的数据可能差别很大,因此,建议不要修改默认设置,而是针对某个调用进行单独设置。
useHarmonyMap 方法
- client.useHarmonyMap(value);
- client.useHarmonyMap();
有参数时为设置 useHarmonyMap
的值,无参数时返回 useHarmonyMap
的设置值,该方法的参数和返回值为 Boolean
类型,默认值为 false
。
该方法表示调用所返回的数据中,如果包含有 Map 类型的数据,是否反序列化为 ECMAScript 6 中的 Map
类型对象。当该属性设置为 false
时(即默认值),Map 类型的数据将会被反序列化为 Object
实例对象的数据。
除非 Map 中的键不是字符串类型,否则没必要将该属性设置为 true
。
你也可以针对某个调用进行单独设置。
keepAlive 方法
- client.keepAlive(value);
- client.keepAlive();
有参数时为设置 keepAlive
的值,无参数时返回 keepAlive
的设置值,该方法的参数和返回值为 Boolean
类型,默认值为 true
。
该方法表示客户端和服务器端之间是否保持长连接。该属性对 TCP 和 WebSocket 客户端有效。
filter 方法
- client.filter(value);
- client.filter();
有参数时为设置 filter
的值,无参数时返回 filter
的设置值,该方法的参数和返回值可以为对象类型或对象数组类型。默认值为 null。
该属性的作用是可以设置一个或多个 Filter
对象。关于 Filter
对象,我们将作为单独的章节进行介绍,这里暂且略过。
addFilter 方法
- client.addFilter(filter);
该方法同设置 filter
属性类似。该方法用于添加一个 filter
对象到 Filter 链的末尾。
removeFilter 方法
- client.removeFilter(filter);
该方法同设置 filter
属性类似。该方法用于从 Filter 链中删除指定的 filter
对象。
useService 方法
- client.useService();
- client.useService(uri);
- client.useService(functions);
- client.useService(uri, functions);
该方法的用处是对于未初始化的客户端对象,进行后期初始化设置,或者用于变更服务器地址。
当未设置任何参数调用时,该客户端返回一个 promise
对象,该 promise
对象的成功值为远程服务代理对象。
当仅设置了 uri
参数时,跟上面的功能相同,但是会替换当前的 uri
设置。注意,这里的 uri
地址只能是单个的服务地址,而不能是服务地址数组列表。
functions
参数是一个服务方法列表,与创建客户端时的 functions
参数相同,但不能是单个的字符串方法名。当设置了该列表参数后,会直接返回一个远程服务代理对象。
例如:
- var client = new hprose.HttpClient('http://www.hprose.com/example/', ['hello']);
- client.hello("World", function(result) { console.log(result); });
跟下面的代码的效果完全相同。
- var client = new hprose.HttpClient();
- var proxy = client.useService('http://www.hprose.com/example/', ['hello']);
- proxy.hello("World", function(result) { console.log(result); });
注意,这里的 proxy
对象跟 client
实际上是同一个对象。如果希望有所区别,可以在 useService
方法的最后加上一个 true
的参数。该参数表示创建一个不同于 client
的新的 proxy
对象。
ready 方法
前面在介绍创建客户端的时候已经介绍过了。它的作用是,当远程方法被动态绑定到客户端上后,触发 ready 中的回调函数,执行对远程方法的调用。
invoke 方法
使用远程方法名调用
- client[name]([arg1, arg2, ... argn[, onsuccess[, onerror[, settings]]]]);
name
是要调用的远程函数/方法名。
arg1
…argn
是这个远程函数/方法的参数。如果这个方法没有参数,那就不需要写任何参数。有几个就写几个。参数不能是 function
类型,这一点不难理解,因为一个函数是不能作为参数传给远程服务器执行的。
onsuccess
是远程函数/方法调用成功时的回调函数。它是 function
类型。正是因为前面的参数不可能是 function
类型,因此这里只要遇到第一个是 function
类型的参数,那么就可以认为它是回调函数。
onerror
是远程函数/方法调用失败时的回调函数。它也是 function
类型。它跟在 onsuccess
之后,因此,如果你想传入一个处理失败情况的回调函数,那么 onsuccess
这个回调函数是不能省略的。
settings
是对该远程函数/方法的单独设置,这里面包括前面介绍属性时提到的那些可以单独设置的属性,还有几个是属性中不具有而特别针对调用时的设置。因为该参数是一个对象,因此,它之前的 onsuccess
参数也不能省略(但是 onerror
可以省略),否则它无法被识别为是远程方法的参数还是远程方法的设置。
使用 invoke 调用
- client.invoke(name[, args[, onsuccess[, onerror[, settings]]]]);
该方法是客户端的最核心方法,它的功能就是进行远程调用,并返回一个表示结果的 promise
对象。
该方法与直接使用远程方法名调用功能类似。但有以下几点区别:
- 直接使用远程方法名调用时,参数 arg1…argn 中的参数可以是 promise 对象。直接使用 invoke 方法时,args 是参数数组,里面的元素不可以包含 promise 对象。
- 当同时使用远程方法名和 invoke 方法进行远程调用时,不管哪个写在前面,都是 invoke 方法先执行,原因是使用远程方法名调用时,会先对对参数中的 promise 对象进行取值操作,而 invoke 方法调用不会有这个过程。
- invoke 方法的 args 必须是数组类型,但可以省略,省略的话,被认为该调用没有参数。
invoke 方法的 onsuccess 在省略的情况下,仍然可以带入 settings 参数。但直接使用远程方法名调用时,如果 onsuccess 省略,则不能带入 settings 参数。
settings
参数可以包括以下设置:
mode
下面来分别介绍一下这些设置的意义:
mode
该设置表示结果返回的类型,它有4个取值,分别是:
- hprose.Normal (或 hprose.ResultMode.Normal)
- hprose.Serialized (或 hprose.ResultMode.Serialized)
- hprose.Raw (或 hprose.ResultMode.Raw)
- hprose.RawWithEndTag (或 hprose.ResultMode.RawWithEndTag)
hprose.Normal
是默认值,表示返回正常的已被反序列化的结果。
hprose.Serialized
表示返回的结果保持序列化的格式。
hprose.Raw
表示返回原始数据。
hprose.RawWithEndTag
表示返回带有结束标记的原始数据。
这样说明也许有些晦涩,让我们来看一个例子就清楚了:
- var client = hprose.Client.create('http://www.hprose.com/example/', ['hello']);
- function onsuccess(result) {
- console.log(result);
- }
- client.hello("World", onsuccess, { mode: hprose.Normal, sync: true });
- client.hello("World", onsuccess, { mode: hprose.Serialized, sync: true });
- client.hello("World", onsuccess, { mode: hprose.Raw, sync: true });
- client.hello("World", onsuccess, { mode: hprose.RawWithEndTag, sync: true });
为了保证执行顺序,这里还加了一个 sync
设置,对于该设置在后面再做详细解释。
该程序执行结果如下:
'Hello World'
's11"Hello World"'
'Rs11"Hello World"'
'Rs11"Hello World"z'
由于历史原因,为了兼容旧版本的 hprose 的写法,该设置也可以不写在 settings
对象中,例如上面程序还可以这样写:
- var client = hprose.Client.create('http://www.hprose.com/example/', ['hello']);
- function onsuccess(result) {
- console.log(result);
- }
- client.hello("World", onsuccess, hprose.Normal, { sync: true });
- client.hello("World", onsuccess, hprose.Serialized, { sync: true });
- client.hello("World", onsuccess, hprose.Raw, { sync: true });
- client.hello("World", onsuccess, hprose.RawWithEndTag, { sync: true });
但在新版本中,不再推荐这种写法。
byref
该设置表示调用是否为引用参数传递方式。例如:
- var client = hprose.Client.create('http://www.hprose.com/example/',
- ['swapKeyAndValue']);
- var weeks = {
- 'Monday': 'Mon',
- 'Tuesday': 'Tue',
- 'Wednesday': 'Wed',
- 'Thursday': 'Thu',
- 'Friday': 'Fri',
- 'Saturday': 'Sat',
- 'Sunday': 'Sun'
- };
- function onsuccess(result, args) {
- console.log(weeks.constructor, weeks);
- console.log(result.constructor, result);
- console.log(args.constructor, args);
- }
- client.swapKeyAndValue(weeks, onsuccess, { byref: true });
该程序执行结果为:
[Function: Object] { Monday: 'Mon',
Tuesday: 'Tue',
Wednesday: 'Wed',
Thursday: 'Thu',
Friday: 'Fri',
Saturday: 'Sat',
Sunday: 'Sun' }
[Function: Object] { Mon: 'Monday',
Tue: 'Tuesday',
Wed: 'Wednesday',
Thu: 'Thursday',
Fri: 'Friday',
Sat: 'Saturday',
Sun: 'Sunday' }
[Function: Array] [ { Mon: 'Monday',
Tue: 'Tuesday',
Wed: 'Wednesday',
Thu: 'Thursday',
Fri: 'Friday',
Sat: 'Saturday',
Sun: 'Sunday' } ]
我们可以看到在回调方法中的 args
参数被改变了,但是原来的参数对象 weeks
并没有被改变。也就是说,这里的引用参数传递只体现在回调函数返回的参数上,对原始的参数并不会修改。
同样,由于历史原因,为了兼容旧版本的 hprose 的写法,该设置也可以不写在 settings
对象中,而直接将 true
跟在 onsuccess
之后也是可以的。
binary
该设置表示本次调用中所传输的参数是否包含二进制数据。前面在方法介绍中已经进行了说明,这里就不在重复。
simple
该设置表示本次调用中所传输的参数是否为简单数据。前面在方法介绍中已经进行了说明,这里就不在重复。
failswitch
该设置表示当前调用在因网络原因失败时是否自动切换服务地址。
timeout
该设置表示本次调用的超时时间,如果调用超过该时间后仍然没有返回,则会以超时错误返回。
idempotent
该设置表示本次调用是否为幂等性调用,幂等性调用在因网络原因调用失败时,会自动重试。
retry
该设置表示幂等性调用在因网络原因调用失败后的重试次数。只有 idempotent
设置为 true
时,该设置才有作用。
oneway
该设置表示当前调用是否不等待返回值。当该设置为 true
时,请求发送之后,并不等待服务器返回结果,回调函数将立即被调用,结果被设置为 undefined
。
sync
该设置表示当前调用是否为“同步”调用。这里的“同步”调用是伪同步。它仅表示在该调用之后,同一个客户端所发起的其它远程调用一定是在本次调用执行完之后才会被调用。它可以保证几个连续的调用将按书写顺序执行。但每个调用本身还是异步的。
onsuccess
该设置表示调用成功时的回调函数,跟 invoke
方法的 onsuccess
参数是一个意思。它通常不会在 settings
参数中设置,因为在使用方法名调用时,没有 onsuccess
参数的情况下,无法传递 settings
参数。但是如果在 settings
参数中也设置了该属性,那么它将会覆盖 invoke
方法的 onsuccess
参数的设置。
onerror
该设置表示调用失败时的回调函数,跟 invoke
方法的 onerror
参数是一个意思。它通常也不会在 settings
参数中设置。但是如果在 settings
参数中也设置了该属性,那么它将会覆盖 invoke
方法的 onerror
参数的设置。
useHarmonyMap
该设置跟前面介绍的 useHarmonyMap
属性功能相同,但只针对当前调用有效。
userdata
该属性是一个对象,它用于存放一些用户自定义的数据。这些数据可以通过 context
对象在整个调用过程中进行传递。当你需要实现一些特殊功能的 Filter 或 Handler 时,可能会用到它。
上面这些设置除了可以作为 settings
参数的属性传入以外,还可以在远程方法上直接进行属性设置,这些设置会成为 settings
参数的默认值。例如上面那个引用参数传递的例子还可以写成这样:
- var client = hprose.Client.create('http://www.hprose.com/example/',
- ['swapKeyAndValue']);
- var weeks = {
- 'Monday': 'Mon',
- 'Tuesday': 'Tue',
- 'Wednesday': 'Wed',
- 'Thursday': 'Thu',
- 'Friday': 'Fri',
- 'Saturday': 'Sat',
- 'Sunday': 'Sun',
- };
- client.swapKeyAndValue.onsuccess = function(result, args) {
- console.log(weeks.constructor, weeks);
- console.log(result.constructor, result);
- console.log(args.constructor, args);
- };
- client.swapKeyAndValue.byref = true;
- client.swapKeyAndValue(weeks);
运行结果是一样的。这里就不在重复了。
链式调用
因为 invoke 方法的返回值是一个 promise
对象,因此它可以进行链式调用,例如:
- var client = hprose.Client.create('http://www.hprose.com/example/', ['sum']);
- client.sum(1, 2)
- .then(function(result) {
- return client.sum(result, 3);
- })
- .then(function(result) {
- return client.sum(result, 4);
- })
- .then(function(result) {
- console.log(result);
- });
该程序的结果为:
10
更简单的顺序调用
前面我们讲过,当使用方法名调用时,远程调用的参数本身也可以是 promise
对象。
因此,上面的链式调用还可以直接简化为:
- var client = hprose.Client.create('http://www.hprose.com/example/', ['sum']);
- client.sum(client.sum(client.sum(1, 2), 3), 4).then(function(result) {
- console.log(result);
- });
这比上面的链式调用更加直观。尤其是当一个调用的参数依赖于其它几个调用的结果时候,例如:
- var wrap = hprose.Future.wrap,
- client = hprose.Client.create('http://www.hprose.com/example/', ['sum']),
- log = wrap(console.log, console),
- r1 = client.sum(1, 3, 5, 7, 9),
- r2 = client.sum(2, 4, 6, 8, 10),
- r3 = client.sum(r1, r2);
- log(r1, r2, r3);
这个程序的运行结果为:
25 30 55
该程序虽然是异步执行,但是书写方式却是同步的,不需要写任何回调。
而且这里还有一个好处,r1
和 r2
两个调用的参数之间没有依赖关系,是两个相互独立的调用,因此它们将会并行执行,而 r3
的调用依赖于 r1
和 r2
,因此 r3
会等 r1
和 r2
都执行结束后才会执行。也就是说,它不但保证了有依赖关系的调用会根据依赖关系顺序执行,而且对于没有依赖的调用还能保证并行执行。
这是回调方式和链式调用方式都很难做到的,即使可以做到,也会让代码变得晦涩难懂。
这也是 hprose 2.0 最大的改进之一。
批处理调用
- client.batch.begin();
- ...
- client.batch.end([settings]);
通过这两个方法,可以实现批处理调用。例如:
- var client = hprose.Client.create('http://www.hprose.com/example/', ['hello']);
- function onsuccess(result) {
- console.log(result);
- }
- client.batch.begin();
- client.hello("World", onsuccess, { mode: hprose.Normal });
- client.hello("World", onsuccess, { mode: hprose.Serialized });
- client.hello("World", onsuccess, { mode: hprose.Raw });
- client.hello("World", onsuccess, { mode: hprose.RawWithEndTag });
- client.batch.end({ idempotent: true });
运行结果为:
'Hello World'
's11"Hello World"'
'Rs11"Hello World"'
'Rs11"Hello World"z'
需要注意的是,虽然这里结果的显示顺序跟调用的顺序完全相同,但是这并不代表在服务器端这些方法是顺序执行的。
批处理调用的功能是可以在一个请求中同时发送多个调用,这多个调用在服务器端并发执行,最后汇总结果一次性返回。
因此,批处理调用的方法之间不能有前后依赖的顺序。
因此前面这个例子:
- var wrap = hprose.Future.wrap,
- client = hprose.Client.create('http://www.hprose.com/example/', ['sum']),
- log = wrap(console.log, console),
- r1 = client.sum(1, 3, 5, 7, 9),
- r2 = client.sum(2, 4, 6, 8, 10),
- r3 = client.sum(r1, r2);
- log(r1, r2, r3);
r3
和 r1
、r2
之间有先后依赖关系,因此,这三个调用是不能同时放在批处理调用中的。但是 r1
和 r2
之间并没有依赖关系,所以,它们两个可以放在批处理调用中。
另外需要注意的一点是,在批处理调用的设置中,以下选项仅在每个单独的调用中设置有效:
- mode
- byref
- simple
- onsuccess
- onerror
useHarmonyMap
以下选项仅在endBatch
方法中设置有效:binary
- failswitch
- timeout
- idempotent
- retry
- oneway
- sync
另外,还有一个userdata
选项比较特殊,它在两个里面都可以设置,但两处设置所在的上下文是不同的。
- - - 在 hprose 1.4 到 1.6 的 JavaScript 版本中也实验性的加入了批处理调用支持,旧版本中批处理的 API 是beginBatch
和endBatch
这两个方法,这两个方法都没有参数,这个功能在这些旧版本中有很多限制,因此不推荐在旧版本中使用该功能。在 hprose 2.0 中,beginBatch
和endBatch
这两个方法已废止。请使用新的batch.begin
和batch.end
方法来代替。- - -