flask女服务员/枪支:请求实体太大,无法进行30秒音频文件(WebM)

问题描述 投票:0回答:0

app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB limit

用女服务员绑架烧瓶:

from waitress import serveserve (app, host="127.0.0.1", port=5000, max_request_body_size=100 * 1024 * 1024)

测试gunicorn with gunicorn_config.py:

limit_request_field_size = 0 limit_request_line = 0 timeout = 300 worker_connections = 1000

尽管进行了这些更改,但提交了较大的请求(音频的30秒)仍然触发413错误。
我排除的是:

小型音频文件(〜100 kb)工作正常。
MACOS防火墙被禁用。
我不使用nginx.

代码片段

frontend(JavaScript) - 录制和提交音频
  • function processRecording() { let audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); let reader = new FileReader(); reader.readAsDataURL(audioBlob); reader.onloadend = function () { audioDataInput.value = reader.result; document.querySelector('form').submit(); }; }
  • 后端(提交音频的烧瓶路线)
  • @app.route('/speaking_task_submit', methods=['POST']) def speaking_task_submit(): print(f"Flask MAX_CONTENT_LENGTH: {app.config.get('MAX_CONTENT_LENGTH')} bytes") print(f"Received Content-Length: {request.content_length} bytes") if request.content_length and request.content_length > app.config.get('MAX_CONTENT_LENGTH'): return jsonify({"error": "Request size exceeded!"}), 413 audio_data = request.form['audio_data'] if not audio_data or "," not in audio_data: return jsonify({"error": "Invalid or missing audio data"}), 400 # Save audio as .webm audio_content = audio_data.split(",")[1] audio_file_path = f"uploads/candidate_audio.webm" with open(audio_file_path, "wb") as audio_file: audio_file.write(base64.b64decode(audio_content)) return jsonify({"message": "Audio received successfully"})
  • 环境详细信息:

MACOSMONTEREY

Python3.10
Flask3.1.0

WAITRESS3.0.2
吉尼康23.0.0

    我尝试的是:
  • 用女服务员运行烧瓶,并设置max_request_body_size = 100 * 1024 *1024.
  • 用枪和设置limit_request_field_size =0。 Macos上的任何防火墙或代理限制。
  • 问题:
  • 什么仍然可以限制请求大小?

在女服务员,枪支或烧瓶中还有另一个隐藏的限制 我很想念?

    我应该在烧瓶中配置任何其他中间件设置吗?
  • 任何帮助都非常感谢!
错误消息是由您上传数据的方式产生的。我使用以下代码直接以文件形式上传斑点,没有问题。 所使用的方法对于较大的音频文件更有效,因为FormData对象没有尺寸限制,也不需要解码。数据以二进制格式发送,因此小于Base64编码数据。

from flask import ( Flask, Response, abort, current_app, render_template, redirect, request, stream_with_context, url_for ) from collections import namedtuple from glob import glob from mimetypes import add_type, guess_extension, guess_type from werkzeug.utils import secure_filename import os add_type('audio/aac', '.m4a', strict=True) Record = namedtuple('Record', ('filename', 'created_at')) app = Flask(__name__) app.config.from_mapping( MAX_CONTENT_LENGTH=100*1024*1024, UPLOAD_FOLDER='uploads', ) os.makedirs( os.path.join( app.instance_path, app.config.get('UPLOAD_FOLDER', 'uploads') ), exist_ok=True ) @app.route('/') def audio_index(): patterns = [ '*.m4a', '*.wav', '*.weba' ] path = os.path.join( current_app.instance_path, current_app.config.get('UPLOAD_FOLDER', 'uploads') ) records = [ Record(fn[len(path)+1:], os.path.getctime(fn)) \ for ptrn in patterns for fn in glob(os.path.join(path, ptrn)) ] return render_template('index.html', records=records) @app.post('/audio-upload') def audio_upload(): if 'audio_file' in request.files: file = request.files['audio_file'] extname = guess_extension(file.mimetype) if not extname: abort(400) # Check for allowed file extensions. i = 1 while True: dst = os.path.join( current_app.instance_path, current_app.config.get('UPLOAD_FOLDER', 'uploads'), secure_filename(f'audio_record_{i}{extname}')) if not os.path.exists(dst): break i += 1 file.save(dst) return redirect(url_for('audio_index')) @app.route('/audio/stream/<path:filename>') def audio_download(filename): @stream_with_context def generator(src): CHUNK_SIZE = 8*1024 with open(src, 'rb') as fp: while True: data = fp.read(CHUNK_SIZE) if not data: break yield data src = os.path.join( current_app.instance_path, current_app.config.get('UPLOAD_FOLDER', 'uploads'), filename ) if not os.path.exists(src): return abort(404) mime,_ = guess_type(src) return app.response_class(generator(src), mimetype=mime)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Audio Index</title> </head> <body> <div class="rec-container"> <div class="rec-column rec-column-1"> <button class="rec-btn" id="toggle-rec-btn">Record</button> </div> <div class="rec-column rec-column-2"> {% for record in records|sort(attribute='created_at', reverse=True) -%} <div class="rec-item"> <div class="content"> <span class="rec-title">{{ record.filename }}</span> <audio controls src="{{ url_for('audio_download', filename=record.filename) }}" ></audio> </div> </div> {% endfor -%} </div> </div> <script type="text/javascript"> (function(uploadURL) { const startButton = document.getElementById('toggle-rec-btn'); startButton.addEventListener('click', function() { if (!navigator.mediaDevices) { console.error('MediaDevices not supported.') return; } if (!MediaRecorder.isTypeSupported('audio/webm;codecs=opus')) { console.error('Unsupported media type.'); return; } const constraints = { audio: true }; navigator.mediaDevices.getUserMedia(constraints) .then(function(stream) { let chunks = [] const options = { mimeType: 'audio/webm;codecs=opus' }; const recorder = new MediaRecorder(stream, options); recorder.ondataavailable = event => { chunks.push(event.data); }; recorder.onstop = event => { console.log('Recording stopped.'); let blob = new Blob(chunks, { type: recorder.mimeType }); chunks = []; startButton.disabled = false; let formData = new FormData(); formData.append('audio_file', blob); fetch(uploadURL, { method: 'POST', cache: 'no-cache', body: formData }).then(resp => { if (!resp.ok) { throw new Error('Something went wrong.'); } window.location.reload(true); }).catch(err => { console.error(err); }); }; recorder.onstart = event => { console.log('Recording started.'); startButton.disabled = true; setTimeout(function() { recorder.stop(); }, 30000); }; recorder.start(); }) .catch(function(err) { console.error(err); }); }); })({{ url_for('audio_upload') | tojson }}); </script> </body> </html>
flask gunicorn
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.