You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask项目中JS Fetch请求Headers未生效导致页面宽度传递失败问题求助

Flask项目中JS Fetch请求Headers未生效导致页面宽度传递失败问题求助

看起来你现在卡在了前端传屏幕宽度给Flask后端的环节,而且遇到了请求类型不匹配和拿到HTML而非JSON的问题,我帮你梳理下问题根源和解决办法~

核心问题分析

首先你的逻辑有个关键矛盾:
你的Flask路由/playlist/<playlist_id>同时处理GET和POST请求,但不管是哪种请求,最后都返回渲染好的playlist.html页面。这就导致:

  1. 当你调用request.get_json()时,Flask要求请求的Content-Type必须是application/json,如果请求头没正确生效(或者路由逻辑不对)就会触发415错误;
  2. 就算请求头正确,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 16:57:56