手动执行服务端代码

你可以在客户端任一时间直接执行服务端代码(Server Code)。当直接执行服务端代码时,你还可以传递一些自定义参数。

我们来展示如何执行服务端代码,假设你已经部署了如下所示的服务端代码:

function main(params, context, done) {
  var user = KiiUser.userWithUsername(params.username,
                                      params.password);
  user.register({
    success: function(user) {
      done(user.getUsername());
    },
    failure: function(user, errorString) {
      done(errorString);
    }
  });
}

示例代码 源自 编写服务端代码 一节中的示例。这段代码希望从客户端的自定义参数里获取用户名和密码,然后用这些参数进行注册(实际场景:允许用户帮助他/她的朋友注册新账户)。

请注意,服务端代码中的成功/失败状态和客户端中的是不同的。在此示例代码中,因为客户端将能够成功接收到服务端代码返回的错误信息,所以,无论服务端代码中是否出现异常,客户端的调用都将成功。当客户端无法调用服务端代码时,客户端才会出现异常。在编写代码时,让服务端代码返回成功/失败状态,从而可以让客户端得知服务端代码中是否出现了异常情况。

通过 REST API 执行服务端代码

这是一个通过 REST API 执行服务端代码的示例:

curl -v -X POST \
  -H "Authorization: Bearer {ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  "https://api-cn3.kii.com/api/apps/{APP_ID}/server-code/versions/current/main" \
  -d '{"username": "name_of_my_friend", "password": "password_for_my_friend"}'
  • 我们把 "username" 和 "password" 的值作为待传递的数据。
  • 然后调用 API 执行目标端点("main")。
  • 访问令牌是可选项。如果省略,Kii Cloud 将认为是匿名用户执行了服务端代码。

这将执行服务端代码里的 "main" 函数。在服务端代码的示例中,KiiUser.userWithUsername 方法用到了2个自定义参数。 注意代码中使用了关键字 "username" 和 "password" 来获取相应的值。

将返回如下的内容:

< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Access-Control-Allow-Origin: *
< X-Step-count: 3
< Content-Type: application/json;charset=UTF-8
< Cache-Control: max-age=0
< Content-Length: 27
< Accept-Ranges: bytes
< Date: Tue, 23 Jul 2013 03:57:28 GMT
< X-Varnish: 1572330455
< Age: 0
< Via: 1.1 varnish
< Connection: keep-alive
<
* Connection #0 to host js-box-tmp.internal.kii.com left intact
{"returnedValue":"name_of_my_friend"}
* Closing connection #0

你可以看到返回结果放在 "returnedValue" 字段里,同时已执行的步骤数放在 "X-Step-count" 头部里。

服务端代码可以返回其它数据类型作为执行结果,下表阐述了执行结果是如何被返回到客户端(此处,我们假设异步模式中用于返回结果的回调函数的名字是 "done").

同步代码中的声明 异步代码中的声明 响应中的返回值
return 1; done(1); {"returnedValue":1}
return "resp"; done("resp"); {"returnedValue":"resp"}
return true; done(true); {"returnedValue":true}
return {name:"Kii", zip:"123456"}; done({name:"Kii", zip:"123456"}); {"returnedValue":{name:"Kii", zip:"123456"}}
return ["one", "two"]; done(["one", "two"]); {"returnedValue":["one", "two"]}

超时

限制 一节中所述,当服务端代码的执行时间超过了 2000 毫秒时,就会发生超时。

当发生超时时,Kii Cloud 通常会响应 400:

{
  "errorCode" : "ENDPOINT_INVOCATION_ERROR",
  "message" : "Error found while executing the developer-defined code",
  "details" : {
    "errorCode" : "EXECUTION_TIMEOUT",
    "message" : "execution timeout. limit=20000ms"
  }
}

服务端代码的语法 一节中所述,如果你设置了超时的返回值,则不会响应 400 而是 200。此时,服务端代码中指定的返回值将被设置在 _timeoutResponse 中:

{
  "returnedValue":{
    "_timeoutResponse":{
      "customField": "my_custom_message"
    }
  }
}

你可以像获得 正常执行结果 那样获得超时的返回结果。

通过 Android SDK 执行服务端代码

下面是通过 Android SDK 执行服务端代码的示例:

  • // Instantiate with the endpoint.
    KiiServerCodeEntry entry = Kii.serverCodeEntry("main");
    
    try {
      JSONObject rawArg = new JSONObject();
    
      // Set the custom parameters.
      rawArg.put("username", "name_of_my_friend");
      rawArg.put("password", "password_for_my_friend");
      KiiServerCodeEntryArgument arg = KiiServerCodeEntryArgument
          .newArgument(rawArg);
    
      // Execute the Server Code
      KiiServerCodeExecResult res = entry.execute(arg);
    
      // Parse the result.
      JSONObject returned = res.getReturnedValue();
      String newUser = returned.getString("returnedValue");
    
      // Get the number of the executed steps.
      int steps = res.getExecutedSteps();
    
    } catch (AppException e) {
      // Handle the error.
    } catch (IOException e) {
      // Handle the error.
    } catch (JSONException e) {
      // Handle the error.
    }
  • // Instantiate with the endpoint.
    KiiServerCodeEntry entry = Kii.serverCodeEntry("main");
    
    JSONObject rawArg = new JSONObject();
    try {
      // Set the custom parameters.
      rawArg.put("username", "name_of_my_friend2");
      rawArg.put("password", "password_for_my_friend");
    } catch (JSONException e) {
      // Handle the error.
    }
    KiiServerCodeEntryArgument arg = KiiServerCodeEntryArgument
        .newArgument(rawArg);
    
    // Execute the Server Code
    entry.execute(arg, new KiiServerCodeEntryCallback() {
      public void onExceuted(KiiServerCodeEntry entry, KiiServerCodeEntryArgument argument,
                             KiiServerCodeExecResult res, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Parse the result.
        try {
          JSONObject returned = res.getReturnedValue();
          String newUser = returned.getString("returnedValue");
    
          // Get the number of the executed steps.
          int steps = res.getExecutedSteps();
        } catch (JSONException e) {
          // Handle the error.
        }
      }
    });

代码简介:

  • 传递目标端点(函数)名给 serverCodeEntry 方法创建一个 KiiServerCodeEntry 实例。
  • 准备自定义参数(此处是 "username" 和 "password"),将这些自定义参数放到一个 JSON 中,并将这个 JSON 传递给 newArgument 方法创建一个 KiiServerCodeEntryArgument 实例。确保此处所使用的参数名和服务端代码中的一致,这样服务器才能正确获取参数值(此处参数名是 "username" 和 "password" )。
  • 传递 KiiServerCodeEntryArgument 实例给 execute 方法执行服务端代码。
    • 如果用户已经登录,Kii Cloud 将认为是这个用户执行了服务端代码。
    • 如果没有用户登录,Kii Cloud 将认为是匿名用户执行了服务端代码。
  • 调用 getReturnedValue 方法获取返回的结果。
  • (可选)调用 getExecutedSteps 方法获取已执行的步骤数。

getReturnedValue 方法将返回一个 JSON,结果存放在 "returnedValue" 字段里(示例请查阅 此部分)。 请使用适当的方法获取实际结果。例如,此例中我们返回了刚创建的用户名,因为用户名是字符串类型,所以使用了 getString 方法。

如果你的服务端代码返回了 超时的值,同样也可以使用 getReturnedValue 方法获得此值。请查阅 此部分 了解此方法获得的 JSON 对象的格式。

通过 iOS SDK 执行服务端代码

下面是通过 iOS SDK 执行服务端代码的示例:

Objective-C:

  • // Instantiate with the endpoint.
    KiiServerCodeEntry* entry =[Kii serverCodeEntry:@"main"];
    
    // Set the custom parameters.
    NSDictionary* argDict= [NSDictionary dictionaryWithObjectsAndKeys:
                             @"name_of_my_friend", @"username",
                             @"password_for_my_friend", @"password", nil];
    KiiServerCodeEntryArgument* argument= [KiiServerCodeEntryArgument argumentWithDictionary:argDict];
    
    // Execute the Server Code.
    NSError* error = nil;
    KiiServerCodeExecResult* result = [entry executeSynchronous:argument
                                                      withError:&error];
    if (error != nil) {
      // Handle the error.
      return;
    }
    
    // Parse the result.
    NSDictionary *returnedDict = [result returnedValue];
    NSString *newUser = [returnedDict objectForKey:@"returnedValue"];
    
    // Get the number of the exectued steps.
    int execSteps = (int)[result executedSteps];
  • // Instantiate with the endpoint.
    KiiServerCodeEntry* entry =[Kii serverCodeEntry:@"main"];
    
    // Set the custom parameters.
    NSDictionary* argDict= [NSDictionary dictionaryWithObjectsAndKeys:
                             @"name_of_my_friend", @"username",
                             @"password_for_my_friend", @"password", nil];
    KiiServerCodeEntryArgument* argument= [KiiServerCodeEntryArgument argumentWithDictionary:argDict];
    
    // Execute the Server Code.
    NSError* error = nil;
    [entry execute:argument
         withBlock:^(KiiServerCodeEntry *entry, KiiServerCodeEntryArgument *argument, KiiServerCodeExecResult *result, NSError *error) {
      if (error != nil) {
        // Handle the error.
        return;
      }
      // Parse the result.
      NSDictionary *returnedDict = [result returnedValue];
      NSString *newUser = [returnedDict objectForKey:@"returnedValue"];
    
      // Get the number of the exectued steps.
      int execSteps = (int)[result executedSteps];
    }];

Swift 2.3:

  • let entry = Kii.serverCodeEntry("main")
    let argDict = ["username":"name_of_my_friend","password":"password_for_my_friend"]
    let argument = KiiServerCodeEntryArgument(dictionary:argDict)
    
    let result : KiiServerCodeExecResult
    do{
      result = try entry.executeSynchronous(argument)
    }catch(let error as NSError){
      // Handle the error.
      return
    }
    // Parse the result.
    let returnedDict = result.returnedValue()
    let newUser = returnedDict?["returnedValue"];
    
    // Get the number of the exectued steps.
    let execSteps : Int = result.executedSteps()
  • let entry = Kii.serverCodeEntry("main")
    let argDict = ["username":"name_of_my_friend","password":"password_for_my_friend"]
    let argument = KiiServerCodeEntryArgument(dictionary:argDict)
    entry.execute(argument) { (retEntry : KiiServerCodeEntry, retArg : KiiServerCodeEntryArgument?, result : KiiServerCodeExecResult?, error : NSError?) in
      if error != nil {
        // Handle the error.
        return
      }
      // Parse the result.
      let returnedDict = result?.returnedValue()
      let newUser = returnedDict?["returnedValue"];
    
      // Get the number of the exectued steps.
      let execSteps : Int = result!.executedSteps()
    }

Swift 3:

  • let entry = Kii.serverCodeEntry("main")
    let argDict = ["username":"name_of_my_friend","password":"password_for_my_friend"]
    let argument = KiiServerCodeEntryArgument(dictionary:argDict)
    
    let result : KiiServerCodeExecResult
    do{
      result = try entry.executeSynchronous(argument)
    }catch(let error as NSError){
      // Handle the error.
      return
    }
    // Parse the result.
    let returnedDict = result.returnedValue()
    let newUser = returnedDict?["returnedValue"];
    
    // Get the number of the exectued steps.
    let execSteps : Int = result.executedSteps()
  • let entry = Kii.serverCodeEntry("main")
    let argDict = ["username":"name_of_my_friend","password":"password_for_my_friend"]
    let argument = KiiServerCodeEntryArgument(dictionary:argDict)
    entry.execute(argument) { (retEntry : KiiServerCodeEntry, retArg : KiiServerCodeEntryArgument?, result : KiiServerCodeExecResult?, error : Error?) in
      if error != nil {
        // Handle the error.
        return
      }
      // Parse the result.
      let returnedDict = result?.returnedValue()
      let newUser = returnedDict?["returnedValue"];
    
      // Get the number of the exectued steps.
      let execSteps : Int = result!.executedSteps()
    }

代码简介:

  • 传递目标端点(函数)名给 serverCodeEntry 方法创建一个 KiiServerCodeEntry 实例。
  • 准备自定义参数(此处是 "username" 和 "password" ),将这些自定义参数放到一个 NSDictionary 中,并将这个 NSDictionary 传递给 argumentWithDictionary 方法创建一个 KiiServerCodeEntryArgument 实例。确保此处所使用的参数名和服务端代码中的一致,这样服务器才能正确获取参数值(此处参数名是 "username" 和 "password")。
  • 传递 KiiServerCodeEntryArgument 实例给 executeSynchronous 方法执行服务端代码。
    • 如果用户已经登录,Kii Cloud 将认为是这个用户执行了服务端代码。
    • 如果没有用户登录,Kii Cloud 将认为是匿名用户执行了服务端代码。
  • 调用 returnedValue 方法获取结果。
  • (可选)调用 executedSteps 方法获取执行的步骤数。

returnedValue 方法将返回一个 NSDictionary,结果存放在 "returnedValue" 字段里(示例请参见 此部分)。请使用合适的方法提取实际值。

如果你的服务端代码返回了 超时的值,同样也可以使用 returnedValue 方法获得此值。请查阅 此部分 了解此方法获得的 NSDictionary 对象的格式。

通过 Unity SDK 执行服务端代码

下面是通过 Unity SDK 执行服务端代码的示例:

// Instantiate with the endpoint.
KiiServerCodeEntry entry = Kii.ServerCodeEntry("main");

JsonObject rawArg = new JsonObject();

// Set the custom parameters.
rawArg.Put("username", "name_of_my_friend");
rawArg.Put("password", "password_for_my_friend");
KiiServerCodeEntryArgument arg = KiiServerCodeEntryArgument
    .NewArgument(rawArg);

// Execute the Server Code
entry.Execute(arg, (KiiServerCodeEntry retEntry, KiiServerCodeEntryArgument args,
                    KiiServerCodeExecResult result, Exception e) => {
  if (e != null)
  {
    // Handle the error.
    return;
  }
  // Parse the result.
  JsonObject returned = result.ReturnedValue;
  string newUser = returned.GetString("returnedValue");

  // Get the number of the executed steps.
  int steps = result.ExecutedSteps;
});

代码简介:

  • 传递目标端点(函数)名给 ServerCodeEntry 方法创建一个 KiiServerCodeEntry 实例。
  • 将自定义参数(此例中为用户名和密码)放入一个 JSON 中,并用 NewArgument 方法创建一个 KiiServerCodeEntryArgument。确保此处所使用的参数名和服务端代码中的一致,这样服务器才能正确获取参数值(此处参数名是 "username" 和 "password")。
  • 传递自定义参数给 Execute 方法执行服务端代码。
    • 如果用户已经登录,Kii Cloud 将认为是这个用户执行了服务端代码。
    • 如果没有用户登录,Kii Cloud 将认为是匿名用户执行了服务端代码。
  • 使用 ReturnedValue 属性获取结果。
  • (可选)使用 ExecutedSteps 属性获取执行的步骤数。

ReturnedValue 属性将获取一个 JSON,结果放在 "returnedValue" 字段中(示例请参见 此部分)。请使用适当的方法获取实际结果;例如,此例中我们返回了刚创建的用户名,因为用户名是字符串类型,所以使用了 GetString 方法。

如果你的服务端代码返回了 超时的值,同样也可以使用 ReturnedValue 属性获得此值。请查阅 此部分 了解此方法获得的 JSON 对象的格式。

通过 JavaScript SDK 执行服务端代码

下面是通过 JavaScript SDK 执行服务端代码的示例:

// Instantiate with the endpoint.
var entry = Kii.serverCodeEntry("main");

// Set the custom parameters.
var arg = {"username":"name_of_my_friend", "password":"password_for_my_friend"};

// Execute the Server Code
entry.execute(arg,{

    success: function(entry, argument, execResult) {
      // do something now that the user is logged in

      // Parse the result.
      var returned = execResult.getReturnedValue();
      var newUser = returned["returnedValue"];

      // Get the number of the executed steps.
      var steps = execResult.getExecutedSteps();
    },

    failure: function(entry, argument,execResult, anErrorString) {
      // do something with the error response
    }
  }
);

代码简介:

  • 传递目标端点(函数)名给 ServerCodeEntry 方法创建一个 KiiServerCodeEntry 实例。
  • 将自定义参数(此例中为用户名和密码)放入一个 Object 中。确保此处所使用的参数名和服务端代码中的一致,这样服务器才能正确获取参数值(此处参数名是 "username" 和 "password")。
  • 传递自定义参数给 execute 方法执行服务端代码。
    • 如果用户已经登录,Kii Cloud 将认为是这个用户执行了服务端代码。
    • 如果没有用户登录,Kii Cloud 将认为是匿名用户执行了服务端代码。
  • 使用 getReturnedValue 方法获取结果。
  • (可选)使用 getExecutedSteps 方法获取执行的步骤数。

getReturnedValue 方法将获取一个 Object,执行结果在 "returnedValue" 字段中(示例请参见 此部分)。请使用适当的方法获取实际结果;例如,在示例中我们获取了新建用户的用户名。

如果你的服务端代码返回了 超时的值,同样也可以使用 getReturnedValue 属性获得此值。请查阅 此部分 了解此方法获得的 JSON 对象的格式。

通过 Thing SDK Embedded 执行服务端代码

你可以通过使用 Thing SDK Embedded 来执行服务端代码。请查阅 执行服务端代码 一节了解如何执行服务端代码。