While our Web development,Would inevitably have to obtain data from the Web server,In many cases also need to submit the data to the server,Which at the moment,We are used to using JSON formatted data,Because it is easy,This time we look,How to use Swift to send JSON-RPC command and get response。
JSON-RPC
JSON-RPC is a free and lightweight remote procedure call(RPC)protocol。 This specification defines the data structure and the associated processing rules。It is allowed to run based on socket, Many different messaging environments such as http in the same process。The use ofJSON(RFC 4627) As a data format。
When we need to get data from the server when,Either by a URL with information,Or need to use a specific method for submission of information to the server,Common HTTP POST 。
We send JSON requests via HTTP POST to the server object to represent a single RPC call,According to the JSON-RPC rules,We need to pass 4 A basic member:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
jsonrpc //指定JSON-RPC协议版本的字符串,必须准确写为“2.0” method //包含所要调用方法名称的字符串,以rpc开头的方法名,用英文句号(U+002E or ASCII 46)连接的为预留给rpc内部的方法名及扩展名,且不能在其他地方使用。 params //调用方法所需要的结构化参数值,该成员参数可以被省略。 id //已建立客户端的唯一标识id,值必须包含一个字符串、数值或NULL空值。如果不包含该成员则被认定为是一个通知。该值一般不为NULL,若为数值则不应该包含小数。 |
All right,An overview of this information,We can try to write a RPC call:
1 |
{"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1} |
About formatting rules part we introduce so much,For more information, please see the article on JSON-RPC the end of "further reading" links。
Swift's networking requests
In Swift,We use a network request will still be using the Cocoa API,We used NSURLConnection ,Use it sendSynchronousRequest(_:returningResponse:) Approach to network requests,But, unfortunately this method will terminate in OS x 10.11 Got it,So we should try not to use it。
NSURLSession
It was the complete reconstruction of the NSURLConnection ,In iOS 7 Introducing,We use it to replace NSURLConnection ,but,Since reconstruction,Then use a little too different,Now we're going to try to look at using NSURLSession Get the data。
First talk NSURLSession Is not a class,But a factory,It will return a NSURLSessionDataTask ,And we need to call the task .resume() Method to start link,Here we use the NSURLSession of dataTaskWithRequest(_:) Method to produce NSURLSessionDataTask Example。
1 2 3 |
let s = NSURLRequest(URL: NSURL(string: "https://www.logcg.com/")!) NSURLSession.sharedSession().dataTaskWithRequest(s).resume() |
Here we create a pocketed Blog Home Request ,And from the NSURLSession of sharedSession() Method to get the default configuration NSURLSession Example,And then call the dataTaskWithRequest(_:) Technique,The incoming Request ,Because this stuff is parallel way, we call resume() Let it start now。
…… For a while,So perform as if nothing? Yes, that's right,Because we need to get the JSON object returned by the server,So we're going to give dataTaskWithRequest(_:) Method to append a closure-if you don't know what a closure,It does not matter,Is to pass in a function as a parameter,This function is used to get the data:
1 2 3 4 5 6 |
let s = NSURLRequest(URL: NSURL(string: "https://www.logcg.com/")!) NSURLSession.sharedSession().dataTaskWithRequest(s, completionHandler: { (data, res, e) -> Void in let t = NSString(data: data!, encoding: NSUTF8StringEncoding) print(t) }).resume() |
According to dataTaskWithRequest(_:) Method declaration:
1 |
public func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> NSURLSessionDataTask |
Function that we will need to receive three parameters,And cannot return a value,So we actually can also be declared as:
1 2 3 |
func handler (data:NSData?, response:NSURLResponse?, e:NSError?) { //Do something here. } |
In short,In accordance with the above code execution,We can see on the Terminal to get pocketed Home the HTML data。
For more data to be sent in,use NSURLRequest Is not enough,Here we are using a NSMutableURLRequest ,It is NSURLRequest A subclass of,With more features,Adding HTTP headers,Add HTTP Body we need to submit information and:
1 2 3 4 5 6 |
let request = NSMutableURLRequest(URL: NSURL(string: url)!) request.HTTPMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") request.HTTPBody = //我们的 JSON 数据 |
Later we'll submit it to the server。
Swift in JSON
Says,Swift handling of JSON has been disappointing,But we just need a simple RPC call,So it is also not so difficult。
NSJSONSerialization
We pass this object to a JSON object class will be Swift,NSString Swift、NSNumber、NSArray、NSDictionary、NSNull and JSON conversion,Here, we use only NSDictionary Can,Because this is the most convenient。
We just need to write an NSDictionary and then to dataWithJSONObject Method:
1 2 3 |
let data = ["jsonrpc": "2.0", "method": "subtract", "params":"getinfo", "id": 1] request.HTTPBody = try! NSJSONSerialization.dataWithJSONObject(data, options: NSJSONWritingOptions.PrettyPrinted) |
Such,We finished with a JSON-RPC command!
Be JSON-RPC remote call via HTTP
Last thing to do is to send it to!
but,The tests you might need to do in the project rather than a Playground,Because in iOS 9 Apple introduces new features after App Transport Security (ATS),Blocks unsafe default HTTP links,If you test the address is HTTPS does not matter,If your address is HTTP,You need to disable this security mechanism。
Disable App Transport Security (ATS)
Find items in your project properties,And then enter the Info tab,Add a NSAppTransportSecurity Typed Dictionary ,Then NSAppTransportSecurity It adds a NSAllowsArbitraryLoads Key,Corresponding values for Boolean Typed YES 。
If you try to use the CLI project testing,That you could not find Info.plist File ... ... So don't try,Otherwise you will not only not get the desired results,Even the error won't be。
Package type
All right,Do the preliminary preparation,We'll look at how to package a class to make RPC calls:
First, we write a program called JSONRPC Class,Here write a typed methods post :
1 2 3 4 5 6 |
class JSONRPC { class func post (params : NSDictionary, url : String, postCompleted : (succeeded: Bool, msg: String, data:String) -> ()) {} } |
Method of this type to receive a NSDictionary The actual parameters,It is that we want to send the data;Then the server address,Finally receiving a closure,It is used to create callback,The closures include:
One succeeded For you to judge the success of, msg Returns the HTTP Response,If no wrong,The data Contains the returned JSON。
First our incoming information to prepare the data:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let request = NSMutableURLRequest(URL: NSURL(string: url)!) let session = NSURLSession.sharedSession() request.HTTPMethod = "POST" do { request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted) } catch (let e) { print(e) return } request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") |
Then we put data into the,While throwing a closure to perform our function to receive based on the results of the function(That is, the callback function):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in let json = try? NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary guard json != nil else { let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding) print("Error could not parse JSON: \(jsonStr)") postCompleted(succeeded: false, msg:String(response),data: "Error") return } postCompleted(succeeded: true, msg:String(response),data: NSString(data: data!, encoding: NSUTF8StringEncoding)! as String) }).resume() |
In short,End type method is the:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import Foundation class JSONRPC { class func post (params : NSDictionary, url : String, postCompleted : (succeeded: Bool, msg: String, data:String) -> ()) { let request = NSMutableURLRequest(URL: NSURL(string: url)!) let session = NSURLSession.sharedSession() request.HTTPMethod = "POST" do { request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(params, options: NSJSONWritingOptions.PrettyPrinted) } catch (let e) { print(e) return } request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("application/json", forHTTPHeaderField: "Accept") session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in let json = try? NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary guard json != nil else { let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding) print("Error could not parse JSON: \(jsonStr)") postCompleted(succeeded: false, msg:String(response),data: "Error") return } postCompleted(succeeded: true, msg:String(response),data: NSString(data: data!, encoding: NSUTF8StringEncoding)! as String) }).resume() } } |
Test
All right,Eventually we had to test the,Here I run locally a Twisterd client process,If you don't know what it is ... ... See further reading at the end of the article ... ... Anyway,Send RPC command us to it:
1 2 3 4 5 6 7 8 |
let cmd:NSDictionary = ["jsonrpc":"2.0","method":"getinfo","id":"1"] JSONRPC.post(cmd, url: "http://user:pwd@127.0.0.1:28332") { (succeeded, msg, data) -> () in print(succeeded) print(msg) print(data) } |
Eventually,We will get the results:
1 2 3 4 5 6 7 8 9 10 |
true Optional(<NSHTTPURLResponse: 0x600000027620> { URL: http://user:pwd@127.0.0.1:28332/ } { status code: 200, headers { Connection = "keep-alive"; "Content-Length" = 1004; "Content-Security-Policy" = "script-src 'self' 'unsafe-eval'"; "Content-Type" = "application/json"; Date = "Fri, 12 Feb 2016 09:17:17 +0000"; Server = "bitcoin-json-rpc/v0.9.34.0-unk-beta"; } }) {"result":{"version":93400,"protocolversion":70003,"walletversion":60000,"blocks":124132,"timeoffset":0,"connections":25,"addrman_total":13235,"addrman_get":2500,"dht_nodes":111,"dht_global_nodes":444,"proxy":"","ext_port1":28333,"ext_port2":29333,"difficulty":0.01040237,"testnet":false,"public_server_mode":false,"errors":"This is a pre-release test build - use at your own risk","ext_addr_net1":"110.253.91.44","ext_addr_net2":"110.253.91.44","dht_torrents":761,"num_peers":235,"peerlist_size":30526,"num_active_requests":5,"download_rate":8330,"upload_rate":18828,"dht_download_rate":5722,"dht_upload_rate":15055,"ip_overhead_download_rate":1724,"ip_overhead_upload_rate":1974,"payload_download_rate":0,"payload_upload_rate":0,"total_download":123761426,"total_upload":177836912,"total_dht_download":92672437,"total_dht_upload":131644914,"total_ip_overhead_download":19615000,"total_ip_overhead_upload":23216840,"total_payload_download":1263802,"total_payload_upload":791702},"error":null,"id":null} |
Next time you manipulate the results:)
Extended reading
Swift sent through HttpRequest request data in JSON format
NSURLSession, instructions for use and back-office work flow analysis
IOS9 HTTP does not work solution
(Interpret) JSON-RPC 2.0 Specifications(Chinese version)
Original article written by LogStudio:R0uter's Blog » Swift sent through HTTP JSON-RPC command
Reproduced Please keep the source and description link:https://www.logcg.com/archives/1554.html