対象:
Swift4

HTTP GETとPOST(Swift)

アプリからサーバにHTTPでGET、あるいはPOSTリクエストすることは結構あると思う。しかし、それはiOSだとなかなか面倒だったりする。早速GETから。

HTTPリクエストに必要なものはURLRequestとURLSessionの2つである。まずはURLを指定してURLRequestを生成する。次に、URLSessionだが、Webページを取得する等の単純なGETならsharedメソッドから共有のセッションを取得すれば良いだろう。

そして、取得したセッションのdataTaskメソッドにURLRequestを渡して呼び出し、生成されたタスクのresumeメソッドを呼び出せばGETリクエストできる。

        let url = URL(string: "http://192.168.0.xx:8080/")
        let request = URLRequest(url: url!)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if error == nil, let data = data, let response = response as? HTTPURLResponse {
                // HTTPヘッダの取得
                print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                // HTTPステータスコード
                print("statusCode: \(response.statusCode)")
                print(String(data: data, encoding: String.Encoding.utf8) ?? "")
            }
        }.resume()

ただし、接続先がhttpsでなくhttpの場合は、セキュアでないアクセスとしてATSにブロックされてしまうので以下も必要となる。ここでは、すべてのhttpのアクセスを許可しているが、セキュリティ的に問題があるかも知れないので、実際には必要なドメインのみ許可しよう。ATSの詳細についてはこちらをご参照いただければと思う。

    NSAppTransportSecurity
    
        NSAllowsArbitraryLoads
        
    

dataTaskメソッドに渡すcompletionHandlerにはHTTPリクエスト完了時、Data、URLResponse、及びErrorの3つの引数が渡される。DataはHTTPリクエストが成功した場合にサーバから取得したデータ(Body)、URLResponseはHTTPヘッダやHTTPステータスコード、Errorはエラーがなければnilである。

completionHandler(クロージャ)の中ではHTTPレスポンスのうち、Body部分がData(バイト列)として渡される。このDataからHTMLを得るためには、エンコードを指定してStringに変換する必要がある。また、URLResponseはHTTPURLResponseにキャストすることによってstatusCodeを得ることができる。

GETだけでなく、もちろんPOSTも可能だ。GETとの違いはURLRequestのhttpMethodプロパティで"POST"を指定することと、httpBodyプロパティにPOSTするデータを設定することである。

        let url = URL(string: "http://192.168.0.xx:8080/")
        var request = URLRequest(url: url!)
        // POSTを指定
        request.httpMethod = "POST"
        // POSTするデータをBodyとして設定
        request.httpBody = "os=iOS&version=11&language=日本語".data(using: .utf8)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if error == nil, let data = data, let response = response as? HTTPURLResponse {
                // HTTPヘッダの取得
                print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                // HTTPステータスコード
                print("statusCode: \(response.statusCode)")
                print(String(data: data, encoding: .utf8) ?? "")
            }
        }.resume()

このPOSTデータをSinatra(Ruby)で書いたサーバ側で受け取った結果は以下である。

os=iOS
version=11
language=日本語
192.168.0.27 - - [28/Jan/2018:09:14:22 +0900] "POST / HTTP/1.1" 200 19 0.0009
192.168.0.27 - - [28/Jan/2018:09:14:22 JST] "POST / HTTP/1.1" 200 19
- -> /

もちろん、サーバからテキストだけでなくJSONを受け取ることもできる。GETで受け取ったJSON形式のDataをJSONSerialization.jsonObjectメソッドに渡して呼びだ出せば、結果をDictionaryで得ることもできる。

        let url = URL(string: "http://192.168.0.xx:8080/json")
        let request = URLRequest(url: url!)
        let session = URLSession.shared
        session.dataTask(with: request) { (data, response, error) in
            if error == nil, let data = data, let response = response as? HTTPURLResponse {
                // HTTPヘッダの取得
                print("Content-Type: \(response.allHeaderFields["Content-Type"] ?? "")")
                // HTTPステータスコード
                print("statusCode: \(response.statusCode)")
                // JSONからDictionaryへ変換
                let dic = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
                print("name: \(dic["name"] as! String)")
                print("price: \(dic["price"] as! Int)")
            }
        }.resume()

Xcodeのコンソールに表示された結果は以下である。

Content-Type: application/json
statusCode: 200
name: ラーメン
price: 500

確認に使用したRubyのスクリプト(httpserver.rb)も載せておく。これをruby httpserver.rb -o 0.0.0.0 -p 8080で起動した。

require 'sinatra'

get "/" do
  "Hello, World!"
end

post "/" do
  params.each do |key, value|
    puts("#{key}=#{value}")
  end
  "Hello, World!(POST)"
end

get "/json" do
  content_type :json
  { name: "ラーメン", price: 500 }.to_json
end
(2018/01/28)

新着情報
【オープンソースソフトウェア環境構築】Apple silicon Macで開発環境を構築
【Rust Tips】Actix webでJSONをPOSTする
【Rust Tips】コマンドライン引数を取得する

Copyright© 2004-2019 モバイル開発系(K) All rights reserved.
[Home]