Swift 通过 http 发送 JSON-RPC 命令

我们在进行网络开发的时候,难免要从网络服务器中获取数据,很多时候还需要给服务器提交数据,就现在来说,一般我们都会习惯使用 JSON 格式的数据,因为它方便好用,这次我们就一起来看看,如何用 Swift 发送 JSON-RPC 命令并获取回复。

JSON-RPC

JSON-RPC是一个无状态且轻量级的远程过程调用(RPC)协议。 本规范主要定义了一些数据结构及其相关的处理规则。它允许运行在基于 socket, http 等诸多不同消息传输环境的同一进程中。其使用JSONRFC 4627)作为数据格式。

当我们需要从服务器获取数据的时候,要么通过 URL 附带信息,要么就需要使用一些特定的方法给服务器提交信息,比如常见的 HTTP POST 。

我们通过 HTTP 的 POST 来给服务器发送 JSON 请求对象以表示一次 RPC 调用,按照 JSON-RPC 规则,我们需要传入 4 个基本成员:

好了,大概了解了这些信息后,我们就可以尝试写出一个 RPC 调用对象:

关于格式规则部分我们就介绍这么多,要了解更多关于 JSON-RPC 的信息请看文章末尾“延伸阅读”中的相关链接。

Swift 里的网络请求

在 Swift 里边,我们使用网络请求的话还是会使用 Cocoa 里的 API,一般我们常用的即 NSURLConnection ,使用它的 sendSynchronousRequest(_:returningResponse:)  方法来进行网络请求,但不幸的是这个方法将终止在 OS X 10.11 了,所以我们应当尽量不去使用它。

NSURLSession

它是彻底重构过的 NSURLConnection ,在 iOS 7 中引入,我们使用它来替代 NSURLConnection ,不过,既然重构了,那么使用方法也会有些许的不同,现在我们就来尝试看看使用 NSURLSession 获取数据。

首先来说说 NSURLSession 并不是一个类,而是一个工厂,它最终会返回一个 NSURLSessionDataTask ,而我们需要调用 task 的 .resume() 方法来启动链接,这里我们用到 NSURLSession 的 dataTaskWithRequest(_:) 方法来产生 NSURLSessionDataTask 实例。

这里我们创建了一个落格博客首页的 Request ,然后从 NSURLSession 的 sharedSession() 方法直接获取默认配置的 NSURLSession 实例,然后调用其中的 dataTaskWithRequest(_:) 方法,传入 Request ,由于这东西是并行的我们直接顺便调用 resume() 让它立即启动。

……等等,这么执行好像什么也没有?对,由于我们还要得到服务器返回的 JSON 对象,所以我们还要给 dataTaskWithRequest(_:) 方法追加一个闭包进去——如果你不知道什么是闭包,也没关系,其实就是多传入一个函数作为参数,这个函数用来处理获取到的数据:

按照 dataTaskWithRequest(_:) 方法的声明:

我们的函数需要接收三个实际参数,而且不能带有返回值,那么我们的函数实际上也可以单独声明为这样:

总之,按照上边的代码执行,我们就可以在终端看到获取到的落格首页的 HTML 数据了。

对于要发送更多的数据进去,使用 NSURLRequest 必然是不够的,这里我们要使用 NSMutableURLRequest ,它是 NSURLRequest 的一个子类,拥有更多的功能,比如添加 HTTP 头,以及添加我们所需要提交的 HTTP Body 信息:

稍后我们来把它提交到服务器。

Swift 里的 JSON

说起来,Swift 对 JSON 的处理至今也不尽人意,不过好在我们只需要简单地将 RPC 调用封装,所以用起来也不会那么困难。

NSJSONSerialization

我们通过这个类将 Swift 里的对象转换为 JSON 对象,它能把 Swift 里的 NSString、NSNumber、NSArray、NSDictionary、NSNull 与 JSON 互转,这里我们只用到 NSDictionary  就可以了,因为这个最方便。

我们只需要写好一个对应的 NSDictionary 然后传给 dataWithJSONObject 方法即可:

这样,我们的 JSON-RPC 命令就写好了!

通过 HTTP 进行 JSON-RPC 远程调用

最后要做的就是把它发出去了!

不过,这个测试你可能需要在项目而不是 Playground 里做,因为在 iOS 9 以后苹果引入了新特性 App Transport Security (ATS),默认禁止了不安全的 HTTP 链接,如果你测试的地址是 HTTPS 则无所谓,如果你的地址是 HTTP,那你需要先禁用这个安全机制。

禁用 App Transport Security (ATS)

在你的项目当中找到项目的属性,然后进入 Info 选项卡,在里边添加一条 NSAppTransportSecurity 类型的 Dictionary ,然后再在 NSAppTransportSecurity 里边添加一条 NSAllowsArbitraryLoads 键,对应的值为 Boolean 类型的 YES 。

如果你尝试使用 CLI 项目测试,那估计你找不到 Info.plist 文件……所以还是不要尝试了,不然你不但得不到期望的结果,连错误提示都不会得到。

封装一个类型方法

好了,做足了前期的准备,我们来看看如何封装一个类来进行 RPC 调用:

首先我们写一个叫做 JSONRPC 的类,这里边写一个类型方法 post :

这个类型方法接收一个 NSDictionary 的实际参数,它就是我们要发送的数据;然后是服务器的地址,最后接收一个闭包,它用来产生回调,这个闭包包含:

一个 succeeded 用来给你判断是否成功, msg 返回 HTTP Response,如果成功无错,则 data 会包含返回的 JSON。

首先我们根据传入的信息来准备数据:

然后我们把数据传入,同时扔一个闭包进去根据结果来执行我们函数接收的那个函数(也就是回调函数)

总之,最终的类型方法是这样的:

测试

好了,最终我们来测试一下,这里本地我运行了一个 Twisterd 客户端进程,如果你不知道它是什么……就去看看文章末尾的延伸阅读……总之,我们来给它发送 RPC 指令:

最终,我们会得到结果:

接下来就是你操作这些结果的时间了:)

延伸阅读

swift通过HttpRequest请求发送json格式的数据

NSURLSession使用说明及后台工作流程分析

iOS9 HTTP 不能正常使用的解决办法

(译) JSON-RPC 2.0 规范(中文版)

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注