エンジニア

2018.05.11

FlaskのAjax通信でつまずいた話

FlaskのAjax通信でつまずいた話

こんにちは2018年度新卒の清水です!
新人研修でHTML, CSS, JavaScriptを使いwebアプリを作っています。
私はフロントをあまり書いてこなかったので心機一転して学習しています。
ちなみに、学生のときサーバサイドをやってました(JavaとPythonはよく書いてました)。

やりたいこと

  • ブラウザをリフレッシュしてもデータが残るようにしたい
  • ローカルストレージはデータ構造が複雑になりそうなのでRDBでやりたい
  • サーバサイドを書きたい(できればPython)

 

方針

  • Ajax通信を使いロード時にデータを取得
  • RDBはMySQLを使用 理由:以前よく使っていた、SQL書きたい
  • サーバサイドはPythonのflaskを使用 理由:APIを作ったことがある

 

コード

Python

バージョンは3.6.5です
flaskをインストールします

pip3 install flask

MySQLからデータを取得するところは省きます

# coding: UTF-8
from flask import Flask, make_response
import json
import db_conect
api = Flask(__name__)
@api.route('/', methods=['GET'])
def get_user():
    row = db_conect.get_task()
    res_json = {
        'title' : row[2],
        'details': row[3],
        'limit': str(row[4]),
        'insert': str(row[5]),
    }
    return make_response(json.dumps(res_json, ensure_ascii=False))
if __name__ == '__main__':
    api.run(host='localhost', port=8080)

とりあえず curlコマンドでjsonが取得できるかテストします

curl http://localhost:8080/ | jq .
{
  "title": "リスト作成",
  "details": "html, css, jsを使う",
  "limit": "2018-05-05 00:00:00",
  "insert": "2018-04-29 00:41:17"
}

ちゃんと取れました

HTML JavaScript

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>Ajax練習</h1>
    <p>アクセス先 : http://localhost:8080/ </p>
    <p>リクエストメソッド : GET</p>
    <input type="text" class="input">
    <button class='get-btn'>ボタン</button>
    <div class="info"></div>
    <script src="http://code.jquery.com/jquery-3.3.1.js"></script>
    <script src="test.js"></script>
</body>
</html>

JavaScript

$(function() {
    $('.get-btn').on('click', () => {
        //http通信開始
        $.ajax({
            url: "http://localhost:8080/",
            dataType: "json",
            type: "GET",
        }).done(function(res) {
            console.log(res)
        }).fail(function(res) {
            console.log(res)
        });
    });
});

ボタンが押されたらajax通信をしてjsonを取得します
見た目はこのように

いざ実行

Chromeのデベロッパーツールを使用してテストを見ていきます
おや?エラーを吐きました

翻訳すると

要求されたリソースに「Access-Control-Allow-Origin」ヘッダーが存在しません。
したがって、原点「ヌル」はアクセスが許可されません。

なんだかよくわかりませんね
Access-Control-Allow-Origin + flask でググっていると以下のサイトを見つけました
Javascript – No ‘Access-Control-Allow-Origin’ header is present on the requested resource

どうやらPython3系以降は pip install flask-corsでflask-corsを使用して解決するそうです。
私はpip3 install flask-corsで入れました。

# coding: UTF-8
from flask import Flask, make_response
from flask_cors import CORS #追加
import json
import db_conect
api = Flask(__name__)
CORS(api) #追加
# 以下同文

いざ実行(二度目)

解決していない…なぜだ

前記したサイトにはPython2系の解決法も記載されていたのでこちらもテスト

# coding: UTF-8
from flask import Flask, make_response
import json
import db_conect
api = Flask(__name__)
# 追加
@api.after_request
def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
  return response
# 以下同文

いざ実行(三度目の正直)

ついに成功!
なぜPython2系の解決法で成功したのかは不明

結局何が問題だったの?

  • Access-Control-Allow-Originがサーバ側で許可されないないのが問題だった
  • Access-Control-Allow-Origin', '*'を設定することにより、任意のドメインがサイト間でアクセスできるようになる

だんだん調べて行くとSame-Origin Policy(同一生成元ポリシー)やCORS(Cross-Origin Resource Sharing)制限などのネットワーク用語が出てきたので理解できるよう努力していきたいと思っています。

一覧に戻る