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

如何用FastAPI+Nextjs不本地保存显示Matplotlib以太坊余额图表?

Next.js + FastAPI 以太坊余额图表生成报错(Internal Server Error)

我用Next.js搭建前端、FastAPI搭建后端开发网站,前端设有以太坊地址输入表单,后端根据输入地址生成「以太坊余额随时间变化」的Matplotlib图表,要求不本地保存图表,直接通过FastAPI返回给前端。目前访问localhost:8000/images时出现「Internal Server Error」,无法正常显示图表,相关代码如下:

前端Next.js代码(Chart.tsx)

fetch("http://localhost:8000/image", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(ethAddress),
    }).then(fetchEthAddresses);

后端图表生成代码(ethBalanceTracker.py)

# Imports
# Logic for chart here

        plt.plot(times, balances)
        buf = BytesIO()
        plt.savefig(buf, format="png")
        buf.seek(0)

        return StreamingResponse(buf, media_type="image/png")

后端FastAPI代码(api.py)

@app.get("/image")
async def get_images() -> dict:
    return {"data": images}

@app.post("/image")
async def add_image(ethAddress: dict) -> dict:

    test = EthBalanceTracker.get_transactions(ethAddress["ethAddress"])
    images.append(test)

问题分析

  1. API逻辑错误:POST接口将StreamingResponse对象存入images数组后未返回有效响应,且GET接口返回的是包含响应对象的数组,无法直接作为图片资源解析。
  2. Matplotlib环境问题:非交互式环境下未指定渲染后端,可能触发显示相关报错。
  3. 前端请求逻辑错误:POST请求后未直接处理返回的图片流,而是调用GET接口获取无效数据。

修复方案

1. 修正FastAPI接口逻辑

删除无用的GET接口,让POST接口直接返回生成的图表流:

# api.py
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from ethBalanceTracker import EthBalanceTracker

app = FastAPI()

@app.post("/image")
async def generate_image(request: Request):
    data = await request.json()
    eth_address = data.get("ethAddress")
    return EthBalanceTracker.get_transactions(eth_address)

2. 配置Matplotlib非交互式后端

在ethBalanceTracker.py开头添加后端配置,并释放图表资源:

import matplotlib
matplotlib.use('Agg')  # 指定非交互式渲染后端
import matplotlib.pyplot as plt
from io import BytesIO
from fastapi.responses import StreamingResponse

# 实现get_transactions方法
def get_transactions(eth_address):
    # 这里补充获取times和balances的业务逻辑
    times = []  # 替换为你的时间数据
    balances = []  # 替换为你的余额数据
    
    plt.plot(times, balances)
    buf = BytesIO()
    plt.savefig(buf, format="png")
    buf.seek(0)
    plt.close()  # 关闭图表,释放内存资源
    return StreamingResponse(buf, media_type="image/png")

3. 调整前端请求处理逻辑

直接处理POST返回的图片流,生成可显示的URL:

// Chart.tsx
import { useState } from 'react';

export default function Chart() {
  const [ethAddress, setEthAddress] = useState('');
  const [chartImageUrl, setChartImageUrl] = useState('');

  const handleGenerateChart = async () => {
    try {
      const response = await fetch("http://localhost:8000/image", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ethAddress }), // 确保发送的是包含字段的对象
      });

      if (!response.ok) throw new Error('生成图表失败');

      const blob = await response.blob();
      const imageUrl = URL.createObjectURL(blob);
      setChartImageUrl(imageUrl);
    } catch (err) {
      console.error(err);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={ethAddress}
        onChange={(e) => setEthAddress(e.target.value)}
        placeholder="输入以太坊地址"
      />
      <button onClick={handleGenerateChart}>生成余额图表</button>
      {chartImageUrl && <img src={chartImageUrl} alt="以太坊余额变化图表" />}
    </div>
  );
}

内容的提问来源于stack exchange,提问作者spal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:15:30