6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

*Android*【HTTP通信_2】FlaskとHTTP通信をする(WebAPIを叩く[GET, POST])

Last updated at Posted at 2020-09-09

はじめに

前回の記事では,httpbinをWebAPIとして使用し,HttpURLConnectionの使い方について解説しました.今回は,FlaskをWebAPIとして使用し,AndroidとFlask間でHTTP通信(GET/POST)を行ってみます.HttpURLConnectionやcurlコマンドの詳しい解説は,前回の記事を参考にしてください.

前提

*Android Studio 4.0.1
*targetSdkVersion 28
*Google Nexus 5x

curlコマンド, Python
*Ubuntu 20.04 LTS (WSL 2)
*Python 3.7.3

GETメソッド

GETメソッドを使ったHTTP通信は簡単に実現できます.Android側は前回の記事を参考にしてください.最後に示すサンプルコードにはAndroid側のコードも記述します.ここではFlask側に関して記述します.

app.py
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/get', methods=['GET'])
def get():
    # GETリクエストに対するレスポンスを作成
    response = {'result': 'success', 'status': 200}
    # JSONオブジェクトとして返す
    return jsonify(response)

curlコマンドを使ってリクエストを送ってみます.

curl http://127.0.0.1:5000/api/get

以下のようなレスポンスが出力されるはずです.

{
  "result": "success",
  "status": 200
}

POSTメソッド

POSTメソッドを使ったHTTP通信について説明します.

flaskでJSON形式のデータを読み込む

JSON形式のデータを読み込む方法としては3つあります.今回は,POSTリクエストで受け取ったデータを読み込むことになります.

app.py
from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/api/post', methods=['POST'])
def post():
    # 方法1
    # POSTで受け取ったデータをrequest.dataを取り出すとbytes型であることがわかる
    print(type(request.data))
    # 出力してもbytes型であることがわかる
    print(request.data)
    # bytes型なので文字列に直すためにdecodeする
    print(request.data.decode('utf-8'))
    # JSON形式で書かれている文字列をloadsメソッドによってディクショナリ型に変換できる
    data = json.loads(request.data.decode('utf-8'))
    print(data)
    
    # 方法2
    # loadsメソッドでは,文字列以外にbytes型,bytearray型を入れることができる
    data = json.loads(request.data)
    print(data)
    
    # 方法3
    # request.jsonメソッドを使うことで,POSTで受け取ったデータをディクショナリ型として扱うことができる
    # この書き方が1番早いので推奨する
    print(request.json)
    
    # 方法3を採用し,戻り値としてJSONオブジェクトを返す
    data = request.json
    return jsonify(data)
    
    
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

app.pyを実行して,試しにcurlを使ってPOSTリクエストを送ってみる.新しいターミナルを開き,以下のコマンドを実行する.bodyは,JSON形式で文字列を記述する.

curl -X POST -H 'Content-Type:application/json' -d `{"name": "foge", "value": "fogefoge"}` http://127.0.0.1:5000/api/post

curlコマンドを実行すると,app.pyを実行したターミナルに以下のように出力される.下3行の出力が同じであることが確認できる.

<class 'bytes'>
b'{"name": "foge", "value": "fogefoge"}'
{"name": "foge", "value": "fogefoge"}
{'name': 'foge', 'value': 'fogefoge'}
{'name': 'foge', 'value': 'fogefoge'}
{'name': 'foge', 'value': 'fogefoge'}

AndroidでのJsonのフォーマット

Androidから送信したJSON形式で書かれた文字列のデータをPythonで読み込むには,Androidの方でJSONの形式に則ってボディを記述する必要がある.具体的には以下のようにする.

String postData = "{\"name\": \"foge\", \"value\": \"fogefoge\"}";

このように,文字列の中に二重引用符を記述する必要があるためエスケープシーケンスを使って記述する.また,文字列の中に変数のデータを埋め込みたい場合は以下のように記述する.

String name = "foge";
int value = 100;

String postData = String.format("{\"name\": \"%s\", \"value\": %d}", name, value);

しかし,このように記述するのは非常に面倒なため,一般的には以下のように記述する.

// 連想配列を作成する
HashMap<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "foge");
jsonMap.put("value", 100);
// 連想配列をJSONObjectに変換
JSONObject responseJsonObject = new JSONObject(jsonMap);
// JSONObjectを文字列に変換
String postData = responseJsonObject.toString();

サンプルコード

では,以下にサンプルコードを示す.

app.py
from flask import Flask, request, jsonify

app = Flask(__name__)
# jsonifyの結果に日本語が含まれる場合,以下の1行を記述することで文字化けを回避できる
app.config['JSON_AS_ASCII'] = False


@app.route('/api/get', methods=['GET'])
def get():
    response = {"result": "success", "status": 200}
    return jsonify(response)
    

@app.route('/api/post', methods=['POST'])
def post():
    data = request.json
    name = data['name']
    value = data['value']
    array = data['array']
    print(f'data: {data}')
    print(f'data["name"]: {name}')
    print(f'data["value"]: {value}')
    print(f'data["array"]: {array}')
    print(f'data["array[0]"]: {array[0]}')
    print(f'data["array[1]"]: {array[1]}')
    print(f'data["array[2]"]: {array[2]}')
    return jsonify(data)
    
    
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Androidのサンプルコードを記述する前にcurlで一度HTTP通信ができるかどうか確認を行ってください.

curl http://127.0.0.1:5000/api/get
curl -X POST -H 'Content-Type:application/json' -d '{"name": "foge", "value": 100, "array":["おはよう", "こんにちは", "こんばんは"]}' http://127.0.0.1:5000/api/post

以下にAndroidのサンプルコードを示します.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.samplehttpconnection">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:gravity="center"
        android:text=""
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="GET"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:gravity="center"
        android:text=""
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="POST"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java
package com.example.samplehttpconnection;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();
    private Button button;
    private Button button2;
    private TextView textView;
    private TextView textView2;
    // IPアドレスは各自変更してください.Pythonのプログラムを実行しているPCのIPアドレスを記述
    private String urlGetText = "http://192.168.0.10:5000/api/get";
    private String urlPostText = "http://192.168.0.10:5000/api/post";
    private String getResultText = "";
    private String postResultText = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
        textView = findViewById(R.id.textView);
        textView2 = findViewById(R.id.textView2);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String response = "";
                        try {
                            response = getAPI();
                            JSONObject rootJSON = new JSONObject(response);
                            getResultText = rootJSON.toString();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView.setText(getResultText);
                            }
                        });
                    }
                });
                thread.start();
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String response = "";
                        try {
                            response = postAPI();
                            JSONObject rootJSON = new JSONObject(response);
                            postResultText = rootJSON.toString();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView2.setText(postResultText);
                            }
                        });
                    }
                });
                thread.start();
            }
        });
    }

    public String getAPI(){
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        String result = "";
        String str = "";
        try {
            URL url = new URL(urlGetText);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setReadTimeout(10000);
            urlConnection.addRequestProperty("User-Agent", "Android");
            urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(false);
            urlConnection.connect();
            int statusCode = urlConnection.getResponseCode();
            if (statusCode == 200){
                inputStream = urlConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                result = bufferedReader.readLine();
                while (result != null){
                    str += result;
                    result = bufferedReader.readLine();
                }
                bufferedReader.close();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }

    public String postAPI(){
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        String result = "";
        String str = "";
        try {
            URL url = new URL(urlPostText);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setReadTimeout(10000);
            urlConnection.addRequestProperty("User-Agent", "Android");
            urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            urlConnection.addRequestProperty("Content-Type", "application/json; charset=UTF-8");
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.connect();
            outputStream = urlConnection.getOutputStream();

            HashMap<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("name", "foge");
            jsonMap.put("value", 100);
            ArrayList<String> array = new ArrayList<>();
            array.add("おはよう");
            array.add("こんにちは");
            array.add("こんばんは");
            jsonMap.put("array", array);
            JSONObject responseJsonObject = new JSONObject(jsonMap);
            String jsonText = responseJsonObject.toString();
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
            bufferedWriter.write(jsonText);
            bufferedWriter.flush();
            bufferedWriter.close();

            int statusCode = urlConnection.getResponseCode();
            if (statusCode == 200){
                inputStream = urlConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                result = bufferedReader.readLine();
                while (result != null){
                    str += result;
                    result = bufferedReader.readLine();
                }
                bufferedReader.close();
            }

            urlConnection.disconnect();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

参照してもらいたいページ

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?