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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

Q&A

解決済

1回答

3835閲覧

Flask+Websocketプロトコルで405エラーが表示されてしまいます

Uka

総合スコア28

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Raspberry Pi

Raspberry Piは、ラズベリーパイ財団が開発した、名刺サイズのLinuxコンピュータです。 学校で基本的なコンピュータ科学の教育を促進することを意図しています。

0グッド

1クリップ

投稿2021/06/12 05:55

編集2021/06/13 15:43

前提・実現したいこと

Flask+Websocketを使ったプログラムを構築しています。ブラウザ上でテキストを入力し、サーバー側で受け取ると、サーバー側で計算した結果をグラフや表にしてブラウザに返すことを想定していす。計算結果のb1,b2はarrayなので、いったんlist形式に変換してからws.sendでブラウザ側に受け渡しています。(リストは浮動少数が多数並んだリストになります)このとき、サーバー側でのテキストの受信や計算等まではうまくいっているようなのですが(コマンドプロンプト上ではエラーはとくにでていません)、計算結果を返す際にブラウザ側で下記のエラーが表示されてしまいます。どこに原因があるかご教示いただけますとありがたいです。よろしくお願いいたします。

発生している問題・エラーメッセージ(ブラウザ上のエラーメッセージ)

Method Not Allowed(405 error) The method is not allowed for the requested URL.

該当のソースコード(test.py)

test.py

1import os 2import json 3import datetime 4import random 5import time 6from gevent import pywsgi 7from geventwebsocket.handler import WebSocketHandler 8from flask import Flask, request, render_template 9import spidev 10import csv 11import threading 12import smbus 13import statistics 14import math 15import numpy as np 16from statistics import mean, median 17import re 18import cv2 19import numpy as np 20from matplotlib import pyplot as plt 21import glob 22#%matplotlib inline 23import math 24import os 25import subprocess 26 27app = Flask(__name__) 28 29@app.route('/') 30def index(): 31 return render_template('index.html') 32 33@app.route('/publish') 34def publish(): 35 36 if request.environ.get('wsgi.websocket'): 37 ws = request.environ['wsgi.websocket'] 38 #message = "" 39 for t in range(0,2): #ブラウザでテキスト入力 40 data11[t] = ws.receive() 41 a11.append(data11[t]) 42 43 print(a11[0]) 44 print(a11[1]) 45 46 #計算過程は省略(計算結果であるb1,b2はarray) 47 48 datas={"result1": b1.tolist(), "result2": b2.tolist()} 49 print(datas) 50 ws.send(json.dumps(datas)) 51 52 return "200 ok" 53 54if __name__ == '__main__': 55 app.debug = True 56 server = pywsgi.WSGIServer(('localhost', 5000), app, handler_class=WebSocketHandler) 57 server.serve_forever()

該当のソースコード(index.html:templatesディレクトリの配下)

index.html

1 2<!DOCTYPE html> 3<html> 4<head> 5 <meta charset="utf-8"> 6 <title>graph test</title> 7 8 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> 9 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script> 10</head> 11 12<style> 13--省略-- 14</style> 15 16<script type="text/javascript"> 17 18$(document).ready(function(){ 19 $('form').submit(function(event){ 20 var inputText=$(".textBox").map(function(index,el){ 21 22 ws.send($(this).val()) 23 console.log($(this).val()) 24 return false; 25 }); 26 }); 27}); 28 29 30var ws = new WebSocket("ws://localhost:5000/publish"); 31// 初期データ 32var data = [[], []]; 33var result_graph = []; 34 35//websocket経由で受け取ったデータをparseしてChart.jsのデータに渡す 36ws.onmessage = function (msg) { 37 38 var obj = JSON.parse(msg.data); 39 console.log(obj.result1, obj.result2); 40 41 result_graph.push({x:obj.resulet1, y:obj.result2}); 42 43 var ctx = document.getElementById('tension-chart').getContext('2d'); 44 var myChart = new Chart(ctx, { 45 type: 'scatter', 46 data: { 47 datasets: [ 48 49 { 50 label: "Result", 51 data: result_graph, 52 pointRadius: 5, 53 pointBorderRadius: 5, 54 borderColor: '#0000ff', 55 //showLine: false, 56 yAxisID: 'first-y-axis', 57 } 58 ] 59 }, 60 options: { 61 title: { 62 display: true, 63 text: "グラフ" 64 }, 65 maintainAspectRatio: false, 66 elements: { 67 line: { 68 tension: 0.5 //Smoothening (Curved) of data lines 69 } 70 }, 71 scales: { 72 xAxes: [{ 73 type: 'linear', 74 position: 'bottom', 75 scaleLabel: { 76 display: true, 77 labelString: 'X', 78 fontFamily: "Arial", 79 }, 80 ticks: { 81 // min: 0.1, 82 // max: 10, 83 // userCallback: function(tick) { 84 // var remain = tick / (Math.pow(10, Math.floor(Chart.helpers.log10(tick)))); 85 // if (remain === 1 || remain === 2 || remain === 5) { 86 // return tick.toString() + ''; 87 // } 88 // return ''; 89 //}, 90 } 91 }], 92 yAxes: [{ 93 id: 'first-y-axis', 94 type:'linear', 95 position: 'left', 96 97 scaleLabel: { // 軸ラベル 98 display: true, // 表示の有無 99 labelString: 'Y', 100 fontFamily: "Arial", 101 }, 102 ticks: { 103 min: 0, 104 max: 0.1, 105 // userCallback: function(tick) { 106 // var remain = tick / (Math.pow(10, Math.floor(Chart.helpers.log10(tick)))); 107 // if (remain === 1) { 108 // return tick.toString() + ''; 109 // } 110 // return ''; 111 // }, 112 } 113 114 },] 115 } 116 }, 117 118 119 120 }); 121 122 var table = document.getElementById("dataTable"); 123 var row = table.insertRow(1); //Add after headings 124 var cell1 = row.insertCell(0); 125 var cell2 = row.insertCell(1); 126 127 cell1.innerHTML = obj.result1; 128 cell2.innerHTML = obj.result2; 129 130}; 131 132</script> 133 134<body> 135 <form method='POST' action='#'> 136 <fieldset class="chart-container" > 137 <legend>入力フォーム</legend> 138 139 <div class="inline-text"><label for="input-sample">テキスト1: </label><input type="text" name='data2' id="Text2" class="textBox" size="7"><font size="-1"> m</font></div> 140 141 <div class="inline-text"><label for="input-sample">テキスト2: </label><input type="text" name='data5' id="Text5" class="textBox" size="7"><font size="-1"> m</font></div> 142 143 144 <div><input type='submit'></div> 145 </fieldset> 146 </form> 147 148 149 <div> 150 <div class="chart-container" position:relative; height:300px; width:100%;><canvas id="result-chart" width="300" height="300"></canvas></div> 151 </div> 152 153 </body> 154<table id="dataTable"> 155 #省略 156 </table> 157 </html>

試したこと

サーバーから計算結果として送信したb1,b2をクライアント側で受信できているかどうかをindex.htmlのconsole.log(obj.result1, obj.result2);で確認しようと思いデベロッパーツールを確認しましたが、ログは何も表示されませんでした。
(追記)
test.pyのws.send(json.dumps(datas))の箇所をwhile True:で括ってみたところ、ブラウザ上で一瞬グラフが表示されましたが、その後405エラーになりました。

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

ここにより詳細な情報を記載してください。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

<form>要素内のボタンクリックでsubmitを行うと、
formaction,methodに基づいてHTTPリクエストを実施します。

Flask側での実装では、@app.routemethodsを指定していないため
GETリクエストしか受け付けていません。
フォーム上ではmethodにPOSTが指定されており、
受付可能なメソッドになっていないために 405レスポンスが返ってきています。


ボタンがクリックされたタイミングにJavaScriptでなにか行う場合は、
onClickイベントなどを使って定義していくのですが、
なんの対策も行わないとJSでの処理後にフォーム自体の処理(HTTPリクエスト)を行います。

そのため、対象のイベントハンドラの最後にreturn falseで、
後続処理をしないことを明示する必要があります。


$('form').submit(function(event){ var inputText=$(".textBox").map(function(index,el){ ws.send($(this).val()) console.log($(this).val()) return false; }); });

質問文のコードでは上記箇所でJS側でのフォーム処理を実装しているのですが、
submitに渡している関数が明示的に何も返していません。
return falseはあるが、$(".textBox").mapないなので無関係)

diff

1$('form').submit(function(event){ 2 var inputText=$(".textBox").map(function(index,el){ 3 4 ws.send($(this).val()) 5 console.log($(this).val()) 6 return false; 7 }); 8+ return false; 9});

上記のようにfunction(event)の返り値としてfalseを返す必要があります。

投稿2021/06/12 11:40

attakei

総合スコア2738

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Uka

2021/06/13 15:30

>attakeiさん 詳細にご回答いただきありがとうございます。 説明が不十分で申し訳ありません、テキストの受け渡しはできているので、ご指摘いただいたjsコードの部分は問題ないと思っています(ブラウザから入力し、サーバー側でa11[0],a11[1]として受け取れていることはprintで確認できています)ただ、そのあとにサーバー側(test.py)で計算を行い、b1,b2をws.sendでクライアント側に受け渡す際に、ブラウザ画面にエラー表示がされます。レスポンスとして送信されたb1,b2の値を使ってグラフ化することが目的なので(その後のデータの更新は想定しておらず、b1,b2を一度だけ送信することを想定しています)、本来はwebsocketを使う必要はないのかもしれませんが、前回別目的で作成したwebsocketプログラムをうまく流用できないかと考えています。そのときはws.send()の箇所をwhile true:で括ってうまく動作していたので、試しに同じようにしてみたところ、ブラウザに一瞬グラフが表示されたあと、405のエラー画面に切り替わりました。データの送信が一度だけのようなケースでは、websocketを使うのはやはり無理があるでしょうか?長文になってしまい、申し訳ございませんが、もし何かアドバイスいただけますとありがたいです。
attakei

2021/06/14 09:24

JSのフォームに対するイベントハンドラは「フォーム送信処理に割り込んで処理をするだけ」という認識をしたほうが良いです。 割り込むだけであって、後続にあるフォーム送信処理は何もしなければ継続して実行されます。 質問文の実装は、あくまで「フォーム送信前に『Websocketにデータを送信する』処理を差し込む」ことだけを行っています。 後続処理に対する対処を何も行っていない以上、「フォーム送信を行う」が実行されます。 回答にもある通りFlask側ではPOSTメソッドのリクエストを受け付けていないため、405エラーが返ってきています。 上記の挙動を止めないといけない というのが回答の主旨です。 Websocket云々は関係ありません。
Uka

2021/06/15 02:01 編集

重ねてご回答くださいましてありがとうございます。回答の趣旨が理解できておらず、申し訳ありませんでした。そもそも、$(document).ready(function(){…の箇所と、後半にある<form method='POST' action='#'>…<input type='submit'>の動作がバッティング?してしまっているということですね、、いろいろなコードを参照しながら書いていたため、コードの動きを把握できていませんでした。ご教示いただいて理解することができました。また、教えていただいた箇所を修正してみたところ、ブラウザにグラフが表示されるようになりました。大変助かりました、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問