Flask项目中JS Fetch请求Headers未生效导致页面宽度传递失败问题求助
Flask项目中JS Fetch请求Headers未生效导致页面宽度传递失败问题求助
看起来你现在卡在了前端传屏幕宽度给Flask后端的环节,而且遇到了请求类型不匹配和拿到HTML而非JSON的问题,我帮你梳理下问题根源和解决办法~
核心问题分析
首先你的逻辑有个关键矛盾:
你的Flask路由/playlist/<playlist_id>同时处理GET和POST请求,但不管是哪种请求,最后都返回渲染好的playlist.html页面。这就导致:
- 当你调用
request.get_json()时,Flask要求请求的Content-Type必须是application/json,如果请求头没正确生效(或者路由逻辑不对)就会触发415错误; - 就算请求头正确,fetch拿到的是整个HTML页面内容,而非期望的JSON数据,自然会出现“Unexpected token '<'”的解析错误——因为它试图把HTML当成JSON来解析。
另外你提到的“DOMContentLoaded执行时机”其实不是核心问题,真正的问题是路由的响应内容不符合fetch的预期。
解决方案推荐
方案一:前端直接判断(最简便,推荐)
其实屏幕宽度是前端专属的属性,完全不需要传给后端判断,直接在前端处理就能省去POST请求的麻烦:
修改playlist.html:
{% for graph in graphs %} <div class="features-graph" id="graph-{{ loop.index }}"> <!-- 默认先加载移动端图片,后续JS根据宽度替换 --> <img src="data:image/jpg;base64,{{ graph[1] }}"> </div> {% endfor %} <script> document.addEventListener('DOMContentLoaded', () => { const screenWidth = window.innerWidth; // 把后端传来的graphs数据转成前端可用的格式 const graphsData = {{ graphs|tojson }}; const graphContainers = document.querySelectorAll('.features-graph'); // 宽度达标就替换成Plotly交互图表 if (screenWidth >= 768) { graphContainers.forEach((container, index) => { container.innerHTML = graphsData[index][0]; }); } }); </script>
修改app.py的路由(去掉POST相关的逻辑,只处理GET渲染):
@app.route('/playlist/<string:playlist_id>', methods=['GET']) def playlist_details(playlist_id): playlist = Playlist.query.filter_by(playlist_id=playlist_id).first_or_404() playlist_tracks = Track.query.filter_by(playlist_id=playlist_id).all() sorted_playlists = model_playlists(playlist_id) graphs = make_graphs(playlist_id) # 只需要把数据传给模板,判断交给前端做 return render_template('playlist.html', playlist=playlist, playlist_tracks=playlist_tracks, model_playlists=sorted_playlists, graphs=graphs)
方案二:修正POST请求+路由逻辑(如果一定要后端处理)
如果你坚持要把宽度传给后端,需要拆分路由职责:一个负责渲染初始页面,一个专门接收POST请求并返回对应内容:
修改app.py:
from flask import jsonify # 处理GET请求,渲染初始页面 @app.route('/playlist/<string:playlist_id>', methods=['GET']) def playlist_details(playlist_id): playlist = Playlist.query.filter_by(playlist_id=playlist_id).first_or_404() playlist_tracks = Track.query.filter_by(playlist_id=playlist_id).all() sorted_playlists = model_playlists(playlist_id) return render_template('playlist.html', playlist=playlist, playlist_tracks=playlist_tracks, model_playlists=sorted_playlists, playlist_id=playlist_id) # 专门处理POST请求,接收宽度并返回对应图表内容 @app.route('/playlist/<string:playlist_id>/get-graphs', methods=['POST']) def get_viewport_graphs(playlist_id): # 先校验请求格式 if not request.is_json: return jsonify({'error': '请求格式必须为JSON'}), 415 data = request.get_json() if 'width' not in data: return jsonify({'error': '缺少width参数'}), 400 viewport_width = data['width'] graphs = make_graphs(playlist_id) content = "" # 根据宽度生成对应的HTML内容 if viewport_width >= 768: for graph in graphs: content += f'<div class="features-graph">{graph[0]}</div>' else: for graph in graphs: content += f'<div class="features-graph"><img src="data:image/jpg;base64,{graph[1]}"></div>' return jsonify({'content': content})
修改playlist.html:
<!-- 留空容器,后续用JS填充图表 --> <div id="graph-container"></div> <script> document.addEventListener('DOMContentLoaded', () => { console.log('dom loaded') const playlistId = '{{ playlist_id }}'; const width = window.innerWidth; const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', }; console.log('Headers being sent:', headers); fetch(`/playlist/${playlistId}/get-graphs`, { method: 'POST', headers: headers, body: JSON.stringify({ width: width }) }) .then(response => { if (!response.ok) { throw new Error(`请求失败:${response.status}`); } return response.json(); }) .then(data => { const graphContainer = document.getElementById('graph-container'); graphContainer.innerHTML = data.content; }) .catch(error => { console.error('Error:', error); }); }); </script>
排查小技巧
可以打开浏览器开发者工具(F12)的Network标签:
- 查看POST请求的Request Headers,确认
Content-Type是否为application/json; - 查看Response内容,判断是不是返回了HTML页面,以此确认路由逻辑是否正确。
备注:内容来源于stack exchange,提问作者nightrainlily
相关产品推荐
相关产品推荐

