Background
作为制作图像识别AI应用程序的练习, 我正在尝试测试一些用于开发它的工具。
为了制作一个简单的图像识别AI应用程序, 我决定采取以下方法:
- 使用HTML5的网络摄像头相关API拍摄主体(前端)
- 使用Python及其一些与ML相关的库来实现此应用程序的核心功能。
- 使用 JavaScript 的
fetch API
和 Python 的Flask
进行前端和后端之间的通信。
我将要使用的工具将是fetch API
,Flask
和HTML + JavaScript
, 所以我尝试制作一个示例代码来测试这些工具的工作原理。
问题
JavaScript 和 Flask 之间通过 http 的通信不起作用。 问题可能是
- 无法将图像数据从JavaScript(前端)发送到Flask(服务器)
- 处理 json 字符串数据有问题。
- 用于http通信的Flask代码和JavaScript代码有问题
更详细,请查看以下代码。
文件和代码
app.py
:定义服务器端函数的烧瓶代码。templates
:app.py
返回到客户端的文件所在的目录。index.html
:相机的HTML + JS代码,并向Flask发送http请求。post.html
:只需显示"hello"即可检查前端和服务器之间的通信是否顺利。
[文件组成]
├── app.py
└── templates
└── index.html
└── post.html
[app.py]
from flask import Flask
from flask import render_template, redirect, send_from_directory, request
from flask import jsonify
app = Flask(__name__)
@app.route('/')
def home():
return render_template("index.html");
@app.route("/tmp",methods=['POST'])
def post():
data = request.get_data()
if not data:
return "no data"
else:
return render_template("post.html")
if __name__ =="__main__":
app.run(debug = True)
[索引.html]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Camera Test</title>
<style>
canvas, video{
border: 1px solid gray;
}
</style>
</head>
<body>
<h1>HTML5カメラ</h1>
<video id="camera" width="300" height="200"></video>
<canvas id="picture" width="300" height="200"></canvas>
<form>
<button type="button" id="shutter">シャッター</button>
<button type="button" id="btn-send">send</button>
</form>
<audio id="se" preload="auto">
<source src="camera-shutter1.mp3" type="audio/mp3">
</audio>
<script>
function sendServer(url, param){
fetch(url, param)
.then((response)=>{
return response.json();
})
.then((json)=>{
if(json.status){
alert("送信に『成功』しました");
setImage(json.result); //json.resultにはファイル名が入っている
}
else{
alert("送信に『失敗』しました");
console.log(`json.status${json.status}`)
console.log(json)
console.log(`[error1] ${json.result}`);
}
})
.catch((error)=>{
alert("送信に『失敗』しました");
//console.log(json)
//console.log(json.result)
console.log(`[error2] ${error}`);
});
}
window.onload = () => {
const video = document.querySelector("#camera");
const canvas = document.querySelector("#picture");
const se = document.querySelector('#se');
/** カメラ設定 */
const constraints = {
audio: false,
video: {
width: 300,
height: 200,
facingMode: "user" // フロントカメラを利用する
// facingMode: { exact: "environment" } // リアカメラを利用する場合
}
};
/**
* カメラを<video>と同期
*/
navigator.mediaDevices.getUserMedia(constraints)
.then( (stream) => {
video.srcObject = stream;
video.onloadedmetadata = (e) => {
video.play();
};
})
.catch( (err) => {
console.log(err.name + ": " + err.message);
});
/**
* シャッターボタン
*/
document.querySelector("#shutter").addEventListener("click", () => {
const ctx = canvas.getContext("2d");
// 演出的な目的で一度映像を止めてSEを再生する
video.pause(); // 映像を停止
se.play(); // シャッター音
setTimeout( () => {
video.play(); // 0.5秒後にカメラ再開
}, 500);
// canvasに画像を貼り付ける
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
});
document.querySelector("#btn-send").addEventListener("click", ()=>{
// Canvasのデータを取得
const pic = canvas.toDataURL("image/png"); // DataURI Schemaが返却される
// 送信情報の設定
const param = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: JSON.stringify({data: pic})
};
const SAVE_URL = "http://localhost:5000/tmp";
// サーバへ送信
console.log(param)
sendServer(SAVE_URL, param);
});
};
</script>
</body>
</html>
[后.html]
<body>
hello
</body>
我现在遇到的确切错误是
- ** 核心问题可能发生在
index.html
sendServer
函数 ** - ** 没有 json 数据附加到来自 Flask 的 http-response**
怎么了?
任何信息将不胜感激。
编辑
202
,当我通过按"发送"按钮发送http请求时弹出的状态代码,因此发送请求(通过POST方法)可能会成功。在这种情况下,有什么问题?我猜sendServer
函数实现错误或 json 的处理是错误的。
C:UsersNaokiyaruzo>python app.py
* Serving Flask app 'app' (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Restarting with stat
* Debugger is active!
* Debugger PIN: 955-089-816
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [19/Sep/2021 13:18:59] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [19/Sep/2021 13:19:01] "GET /camera-shutter1.mp3 HTTP/1.1" 404 -
127.0.0.1 - - [19/Sep/2021 13:19:01] "GET /favicon.ico HTTP/1.1" 404 -
127.0.0.1 - - [19/Sep/2021 13:19:47] "POST /tmp HTTP/1.1" 200 -
已编辑 2
作为回答者的建议,我尝试删除JSONStringify
并将图像数据直接放入 http 请求的body
中,但现在我发现了另一个错误。 [修改]
//index.html
const param = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: {data: pic}
};
[新错误]
SyntaxError: Unexpected token o in JSON at position 1
错误位于sendServer
函数的.catch
部分。
function sendServer(url, param){
fetch(url, param)
.then((response)=>{
return response.json();
})
.then((json)=>{
if(json.status){
alert("送信に『成功』しました");
setImage(json.result); //json.resultにはファイル名が入っている
}
else{
alert("送信に『失敗』しました");
console.log(`json.status${json.status}`)
console.log(json)
console.log(`[error1] ${json.result}`);
}
})
.catch((error)=>{
alert("送信に『失敗』しました");
//console.log(json)
//console.log(json.result)
console.log(`[error2] ${error}`);
});
}
当您怀疑问题出在 Flask 或 sendServer 端时,我也认为问题出在这两个方面,但我无法确认似乎出了什么问题。所以需要解决一些问题,您能否确认请求是否正在发送以及返回的状态代码(您可以在网络选项卡下从烧瓶调试或浏览器调试中检查)浏览器应该显示尝试发送请求的状态代码。
第一个解决方案
因此,如果状态代码为 404,则请求中有问题,通常是数据或发送的 CORS 应该与请求标头一起传递。我怀疑第二种选择,所以我建议您在代码中添加以下内容并再次尝试发送图像(将端口替换为您要从中发送请求的端口或仅保留本地主机)
#app.py
app = Flask(__name__)
CORS(app,resources={r"/*":{"http://localhost:{port}":"*","http://localhost":"*"}})
第二种解决方案
如果第一个解决方案不起作用并且状态代码仍然是 404,那么问题应该出在发送的数据中。尝试在参数中取出(JSON.stringify),看起来像这样,
//index.html
const param = {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8"
},
body: {data: pic}
};