异步调用
===
概述
---
一般情况下,服务端调用API需要等待插件内部执行完成后,才能进行下一步操作。引入异步调用机制,使服务端可以直接跳过等待,由插件在后台执行,而服务端继续进行下一步操作,只需要等待插件执行完成后进行回调,或服务端主动查询调用结果,也可以忽略调用结果。
对于任意API,**均支持被异步调用**。
使用方法
---
例如:
调用API`发送私聊消息「sendPrivateMsg」`
```json
{
"module":"api",
"fun": "sendPrivateMsg",
"qq": 12345,
"msg": "gg"
}
```
* 您可以指定参数`async`为`true`,即
```json
{
"async": true,
"module":"api",
···
}
```
* 也可以在方法名末尾添加`Async`,即
```json
{
"module":"api",
"fun": "sendPrivateMsgAsync",
···
}
```
插件将不会直接返回调用结果
```json
{
"status": 0,
"result": 479,
"request": {
···
}
}
```
而是返回用于**查询调用结果的标识符`asyncID`**,并且状态码(`status`)恒为`0`(success)
```json
{
"status": 0,
"asyncID": 6469864,
"request": {
···
}
}
```
您也可以指定参数`async`为自定义标识符,如
```json
{
"async": 2333,
"module":"api",
···
}
```
但**不建议这样做**,因为在调用结果被服务端取回前,每个标识符都是唯一的,也就是存在冲突。
因此,在标识符产生冲突后,插件会强制生成唯一的随机标识符。
获取调用结果
---
对于任意的异步调用,插件会保留调用结果以供查询,
您可调用`async`模块下的`get`方法,使用标识符作为参数`id`的值获取调用结果
```json
{
"module": "async",
"fun": "get",
"id": 6469864
}
```
如果获取成功,状态码(`success`)为`0`,并且响应(`response`)的值为调用结果,该值与通过非异步方式调用结果一致。
```json
{
"status": 0,
"response": {
"status": 0,
"result": 478,
"request": {
···
}
},
"request": {
"module": "async",
"fun": "get",
"id": 6469864
}
}
```
忽略调用结果
---
您可以选择不查询调用结果,这并不会有任何影响,但强烈建议您在**调用时指定参数`nonCall`为`true`**,
```json
{
"fun": "sendPrivateMsgAsync",
"nonCall": true,
···
}
```
这样插件就不会申请资源用于存储调用结果。
将调用结果回调
---
如果您不想服务端主动查询调用结果,也可**指定参数`callback`为回调URL**。
```json
{
"fun": "sendPrivateMsgAsync",
···
"callback": "http://example.com/callback"
}
```
调用完成后,插件会使用HTTP协议的**POST方法**将调用结果回传给指定的URL。
```
POST /callback HTTP/1.1
Cache-Control: no-cache
Connection: Keep-Alive
Content-Type: application/json; charset=UTF-8
Accept: application/json
Accept-Charset: utf-8
Accept-Language: zh-cn
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Content-Length: 287
Host: example.com
{
"status": -23,
"errmsg": "找不到与目标QQ的关系,消息无法发送",
"asyncID": 44482768,
"request": {
···
}
}
```
如您所见,**回调数据为`json`格式,`UTF-8`编码,并未进行`URL`编码**,和非异步调用结果相似,仅仅是多了`asyncID`。
您也可**在`callback`中指定更多参数**,以适应不同的业务场景。
```json
{
"fun": "sendPrivateMsgAsync",
···
"callback": {
"url": "http://example.com/callback",
"header": "X-Token: This is value.\nX-Forward-To: db.local",
"cookie": "a=b; b=c; c=d",
"proxy": "127.0.0.1:8888",
"paramA": "valueA",
"paramB": "valueB"
}
}
```
| 参数 | 可选 | 说明 |
| :-: | :-: | --- |
| `url` | **×** | 回调URL |
| `header` | √ | HTTP请求头部,多个值请用`\n`换行 |
| `cookie` | √ | HTTP请求Cookie |
| `proxy` | √ | 代理地址,格式:`ip:port` |
**其余参数将作为URL参数进行传递**,
> 本示例中存在参数`paramA`与`paramB`,
> 因此最终请求的URL为`http://example.com/callback?paramA=valueA&¶mB=valueB`。
对于主动连接
---
> 在本小节,主动连接特指**插件通过HTTP协议向服务端发送数据**的连接行为。
在主动连接中异步调用API并无特殊之处,但因为其可一次调用多条API命令,所以**指定参数`async`为自定义标识符时尤其需要注意其唯一性**。当然,如果标识符不唯一,插件同样会生成一个唯一标识符,但如果服务端在回调时依赖该自定义标识符,则您需要特别注意这点。
如果在一条API命令中**指定`callback`参数**,即设置回调URL,则后续调用的**所有命令都会进行回调**,您可指定参数`nonCall`解除回调。
一些补充
---
* 异步调用主要用于设置操作(即`set`、`send`开头的API),
对于用于获取数据(即`get`开头的API),尽可能不使用异步调用,除非设置回调URL回传数据,否则这种操作是无意义。
* 如果**指定参数`callback`或`nonCall`**,则视为异步调用,无论是否指定参数`async`。