質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

cgiは動作するのに値がブラウザで確認できない。

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 416

meron-pan

score 35

 前提・実現したいこと

pythonの標準ライブラリhttp.serverを使ってローカルでサーバーを作り、データの通信実験をしてみました。
しかし、cgiは「CGI script exited OK」と出るのに、POST通信ではブラウザには何も返って来ていないことになっていて困惑しています。
これはコードのミスでした(javascriptで受け取るコードを実行していなかった)のですが、結局受信した結果で例外が発生し、その例外の内容もundefinedになってしまい原因がわかりません。
サーバーに対する知識は全くないので、ネットのありとあらゆる場所からコードを引っ張って作ったコードですが、問題点を教えてください。

 発生している問題・エラーメッセージ

cgiは動作するのに値がブラウザで確認できない。(確認として、POST通信ではない状態で、アクセスしたらhtmlを返すコードを追加しましたところ、「Content-Type:」だけが表示されました。※単純なhtmlのミスでした。スイマセン。修正しました)

 該当のソースコード

cgi

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import io
import os
import sys
import cgi
import cgitb
import urllib.request
import json

cgitb.enable()

sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')


html = ''' 
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<style>
body { background-color: cyan; }
</style>
<title>初めてのpython3CGI</title>
<meta name="description" content="">
<meta name="keywords" content="">
</head>
<body>
<header>
<h1 id="titlename">初めてのpython3CGI</h1>
</header>
<div id="contents">
<article>
<section id="top" style="display:block">
</section>
</article>
</div>
<footer>
</footer>
</body>
</html>
'''

print("Access-Control-Allow-Methods: GET ,POST ,OPTIONS")
print("Access-Control-Allow-Origin: *")
print("Access-Control-Allow-Headers: *")

if os.environ['REQUEST_METHOD'] == 'POST':
 form = cgi.FieldStorage()
 result_json = {'key': 'value'}
 print("Content-Type: application/json; charset=utf-8\r\n")
 print('\n')
 print(json.dumps(result_json))
else:
 print("Content-Type: text/html; charset=utf-8\r\n")
 print('\n')
 print(html)
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>Javascript試験用</title>
    <script charset="UTF-8" type="text/javascript" src="ajax.js"></script>
</head>

<body>
    <div id="outputArea"></div>
    <div id="inputArea">
        <form>
            <textarea name="input" rows="2" cols="20"></textarea>
        </form>
        <button id="ajaxButton" type="button">決定</button>
    </div>
    <div id="dispArea"></div>
</body>

</html>
ajaxSend = function (json) {
    console.log("a")
    var xhr = new XMLHttpRequest();
    xhr.open("POST", 'http://localhost:8000/cgi-bin/server.py', true);
    xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
    xhr.send(json);
  ajaxGet();
}

ajaxGet = function () {
    var req = new XMLHttpRequest();
    try{
        if (httpRequest.readyState === XMLHttpRequest.DONE) {
            if (httpRequest.status === 200) {
              console.log(req.responseText)
              alert(req.responseText);
            }else {
                alert('リクエストに問題が発生しました');
            }
        }
    }
    catch(e){
        alert('例外を補足:'+e.description);
    }
}

json = {
    "messages":
        [
            {
                "date": "2012/1/12 19:12",
                "text": "こんばんは"
            }
            ,
            {
                "date": "2012/1/11 19:12",
                "text": "Hello"
            }
        ]
}

window.onload = function(){
    document.getElementById("ajaxButton").addEventListener('click',function(){ajaxSend(json)})
}

 補足情報(FW/ツールのバージョンなど)

使用しているpythonはpython3.7、ブラウザはfirefox、実行環境はwondows10homeです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • wwbQzhMkhhgEmhU

    2018/10/13 11:32

    サーバーに対する知識は全くないのに、ネットのありとあらゆる場所からコードを引っ張って作ったコードを動かそうとしてるところが問題です。習得にかかる絶対的な時間には個人差がありますが、そのやり方よりは、Hello, World.から順に少しずつできることを増やしていった方が、常人ならよほど早いと思います。例外的にあなたのような方法であっという間に学習される方もいますが、そういう方はそもそも他人に質問するより自分で調べて、瞬間的に解決してしまい、こんなところにいることはありません。

    キャンセル

  • meron-pan

    2018/10/13 15:12

    回答する気が全くないのに、修正依頼で他人を否定することしかできないのであれば、そもそもこんな質問に回答しないでいただきたいですね。知識が欲しいからここで質問しているのですよ。それを「まず先にHello,Worldからできますか?」と聞かれてしまってはこちらも質問していて悲しくなります。

    キャンセル

  • meron-pan

    2018/10/13 15:14

    もし質問内容に不備があるのであれば、修正します

    キャンセル

回答 1

check解決した方法

0

とりあえずですが自己解決しました(超初心者の解決ですが・・・)。フレームワークは一切なしです。
どうやら、pythonのCGIでは、JavaScriptサイドで

xhr.setRequestHeader('Content-Type', 'application/json');

の記述には対応してくれない模様です。

    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');


は反応するっぽいので、これだとjson形式で送信すると値が返ってきませんが、"foo=bar&lorem=ipsum"の形のデータはjavascriptで受け取ることが出来ました(色々と要らない値もセットで来るけど...)。

//どちらか一つにする
var xhr = new XMLHttpRequest();
var req = new XMLHttpRequest();


は送信と受信でセットのようなので、送信と受信で別々に定義したら動かなくなります。

try{
        if (httpRequest.readyState === XMLHttpRequest.DONE) {
            if (httpRequest.status === 200) {
              console.log(req.responseText)
              alert(req.responseText);
            }else {
                alert('リクエストに問題が発生しました');
            }
        }
    }
    catch(e){
        alert('例外を補足:'+e.description);
    }


これは、通信が上手く動作しているかを確認するコードですが、send()した後にすぐにやったら、うまくいかないのは当たり前でした(元のコードをしっかり見ていなかったのが原因でした。xhr.onreadystatechangeのところに貼れば問題ないはず)

下の方に改良をおこなったpythonとjavascriptを貼っておきます。

var xhr = new XMLHttpRequest();//受信と送信で同じものを使わなければならない(要は送信と受信でセット)

ajaxSend = function () {

    xhr.open('POST', 'http://localhost:8000/cgi-bin/server.py', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send("foo=bar&lorem=ipsum");//データはこの形式にしないとCGIで認識してくれない
    ajaxGet()

}

ajaxGet = function () {
        xhr.onreadystatechange = function(){//通信の状態が変化するごとに発火する関数
        console.log(xhr.readyState)//通信状態の確認
        console.log(xhr.responseText)//返ってくる内容(通信の状態が3か4で返ってくる)
    }    
}

window.onload = function(){
    document.getElementById("ajaxButton").addEventListener('click',ajaxSend)
}
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import io
import os
import sys
import cgi
import cgitb
import urllib.request
import json
#エラーをhtml形式でファイルとして吐かせるためのコード
cgitb.enable(display=0, logdir="cgi-bin/tmp")
#文字のエンコード指定
sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

#サーバーにアクセスできているかを確認するためのhtml
html = '''

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<style>
body { background-color: cyan; }
</style>
<title>初めてのpython3CGI</title>
<meta name="description" content="">
<meta name="keywords" content="">
</head>
<body>
<header>
<h1 id="titlename">初めてのpython3CGI</h1>
</header>
<div id="contents">
<article>
<section id="top" style="display:block">
</section>
</article>
</div>
<footer>
</footer>
</body>
</html>
'''
#通信の許可の設定(httpリクエスト:ユーザーには見えないが設定として必要)
print("Access-Control-Allow-Methods: GET ,POST ,OPTIONS")
print("Access-Control-Allow-Origin: *")
print("Access-Control-Allow-Headers: *")

form = cgi.FieldStorage()
#javascriptからのデータの確認のため、テキストファイルに内容を出力させる、デバックにも便利
f = open("cgi-bin/log.txt","w")
f.write(str(form))#formをテキストに変換

#ポスト通信であれば、受け取った内容を、異なるならhtmlを返す
if os.environ['REQUEST_METHOD'] == 'POST':
  print("Content-Type: application/json")
  print("charset=utf-8\r\n")
  print('\n')
  f.write("POST通信")#ポスト通信が行われたのなら、テキストファイルに出力
  print(form)
else:
  print("Content-type: text/html")
  print("charset=utf-8\r\n") 
  print('\n')
  print(html)


f.close()#テキストファイルを閉じる

参考文献
始めましょう - ウェブデベロッパーガイド | MDN

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る