Vue.js POSTでpythonプログラムを動かしてみた


やってみた

環境はAWS EC2 Amazon linux2を使う。そこでDockerでApache2を起動する。
公式ドキュメント
https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html
を見てみたが全然わからなかった。

Dockerfile

  • Apache2でWebページ公開
  • run.sh でApache2起動
  • sample.py の権限を緩めないとPOSTは500 Internal Server Errorで失敗する

サーバーエラーレスポンス一覧
https://developer.mozilla.org/ja/docs/Web/HTTP/Status

FROM ubuntu:18.04

COPY ./src/index.html /var/www/html/
COPY ./src/sample.py /var/www/html
COPY ./run.sh /root/

RUN apt-get update && \
 apt-get -y install apache2 && \
 apt-get -y install python3 && \
 chmod 755 /root/run.sh /var/www/html/sample.py

EXPOSE 80

CMD /root/run.sh
  • sedでapache2.confを編集
    • CGI の実行を可能にするためExecCGIをOptionsに指定
    • pythonファイルをCGIで実行するよう指定するためAddHandler cgi-scriptに.pyを指定

apache2のCGIに関しては以下リンク参照。
https://httpd.apache.org/docs/2.4/ja/howto/cgi.html

run.sh
mkdir -p /var/run/apache2
mkdir -p /var/lock/apache2
. /etc/apache2/envvars

sed 's/^\tOptions Indexes FollowSymLinks/\tOptions Indexes FollowSymLinks ExecCGI/g' /etc/apache2/apache2.conf | \
sed 's/^\tOptions Indexes FollowSymLinks ExecCGI/\tOptions Indexes FollowSymLinks ExecCGI\n\tAddHandler cgi-script .cgi .py/g' > tmp.conf
cp tmp.conf /etc/apache2/apache2.conf
rm tmp.conf

a2enmod cgid
/usr/sbin/apache2 -D FOREGROUND
  • Vueインスタンス内axios.postの第二引数にあるdataを受け取る
  • print関数でVueインスタンスにpythonで行った処理結果を返す
sample.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import cgitb

cgitb.enable()
data = sys.stdin.readline()
print('Content-Type: text/html\n')
print('Hello, ' + data)
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>index</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <input id="input" type="text" value="">
    <input v-on:click="post" id="button" type="button" value="button">
    <p id="res">{{ message }}</p>
  </div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.1/axios.min.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        message: ''
      },
      methods: {
        post: function() {
        var text = document.getElementById("input").value;
        axios.post('./sample.py', {
          type: 'post',
          data: text
        }).then(function(res){
             app.message = res.data;
           }).catch(function(){
                alert('error');
              })
        }
      }
    })
  </script>
</body>
</html>

python cgiについて

https://thinkami.hatenablog.com/category/Python?page=1494886074
↑こちらの記事や
以前自分で書いた記事
https://qiita.com/quryu/items/7c4b1f2dafd1c8ca08a6
ではInternal Server Errorになってしまう。
問題個所は以下のコード。

import cgi

storage = cgi.FieldStorage()
data = storage.getvalue('data')

エラーメッセージ

  File "/var/www/html/sample.py", line 9, in <module>
    storage = cgi.FieldStorage()
  File "/usr/lib/python3.6/cgi.py", line 566, in __init__
    self.read_single()
  File "/usr/lib/python3.6/cgi.py", line 757, in read_single
    self.read_binary()
  File "/usr/lib/python3.6/cgi.py", line 779, in read_binary
    self.file.write(data)
TypeError: write() argument must be str, not bytes

https://lesguillemets.github.io/blog/2014/12/01/python3-cgi-typeerror.html
こちらの記事を参考にしたり色々調べた結果、現在のコードに落ち着いた。
今でもまだ何が悪いのかがわかっていない。

python cgiについて
https://docs.python.org/3/library/cgi.html

参考記事

Vue.js axios を利用した API の使用
https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html

サーバーエラーレスポンス一覧
https://developer.mozilla.org/ja/docs/Web/HTTP/Status

apache Apache Tutorial: CGI による動的コンテンツ
https://httpd.apache.org/docs/2.4/ja/howto/cgi.html

axios CDN
https://cdnjs.com/libraries/axios

Hatena Blog
Docker + Alpine3.5 + Apache2.4 + Python3.6で、フォームのデータを標準モジュールcgiで受け取ってみた
https://thinkami.hatenablog.com/category/Python?page=1494886074

Python3 + cgi.FieldStorage で typerror
https://lesguillemets.github.io/blog/2014/12/01/python3-cgi-typeerror.html

Python Common Gateway Interface support
https://docs.python.org/3/library/cgi.html