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

Docker Compose环境下Deno Fresh前端访问FastAPI后端失败排查

问题描述

使用Docker Compose (V2)启动默认配置的Deno Fresh前端和FastAPI后端,Compose已创建包含两个容器的网络,但前端访问API时遇到以下问题:

  • http://api:5000/ 和 http://localhost:5000/ 均抛出ERR_CONNECTION_REFUSED错误
  • /api:5000/ 返回404 Not Found

只有硬编码服务器地址http://[server]:5000/能正常获取数据,但不想硬编码地址(地址可能变更或未知)。

相关配置文件如下:

docker-compose.yaml

services:
  api:
    build:
      context: ./fast-api
      dockerfile: Dockerfile.fastapi
    ports:
      - "5000:5000"
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.fresh
    ports:
      - "8000:8000"

Fresh组件代码

import { useEffect, useState } from "preact/hooks";

export default function ApiFetch()  {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("http://api:5000/")
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return <div>Hello from {data ? data.Hello : "still loading..."}</div>;
};

已知React可通过package.json配置代理,但Fresh无该文件,也未找到相关官方文档。

问题原因与解决方案

核心原因

  1. 浏览器无法识别Docker内部服务名:前端组件中的fetch是在浏览器端执行的,浏览器属于宿主机网络,不在Docker Compose创建的内部网络中,因此无法解析api这个Docker服务名,导致http://api:5000/请求失败。
  2. FastAPI监听地址限制:如果http://localhost:5000/也无法访问,大概率是FastAPI启动时仅绑定了容器内部的127.0.0.1,而非0.0.0.0,导致宿主机无法访问容器内的5000端口。

解决方案

步骤1:修正FastAPI的监听地址

修改FastAPI的Dockerfile或启动命令,确保服务监听0.0.0.0,允许容器外部(包括宿主机和Docker内部网络)访问:
在Dockerfile.fastapi中,将启动命令改为:

uvicorn main:app --host 0.0.0.0 --port 5000

(默认uvicorn仅监听127.0.0.1,仅容器内部可访问,改为0.0.0.0后才能被外部访问)

步骤2:给Fresh配置API转发(避免硬编码地址)

由于Fresh没有package.json代理配置,可通过服务器端路由转发实现:

  1. 在Fresh项目的routes目录下创建api/[...].ts文件,编写转发逻辑:
import { Handlers } from "$fresh/server.ts";

export const handler: Handlers = {
  async GET(req, ctx) {
    // 提取请求路径,去掉前缀/api后转发到FastAPI服务
    const url = new URL(req.url);
    const apiPath = url.pathname.replace(/^\/api/, "");
    const apiUrl = new URL(`http://api:5000${apiPath}`);

    // 转发请求到FastAPI
    const response = await fetch(apiUrl, {
      method: req.method,
      headers: req.headers,
      body: req.body,
    });

    // 返回FastAPI的响应给浏览器
    return new Response(response.body, {
      status: response.status,
      headers: response.headers,
    });
  },
  // 如需支持POST/PUT等其他方法,添加对应处理逻辑
  async POST(req, ctx) {
    const url = new URL(req.url);
    const apiPath = url.pathname.replace(/^\/api/, "");
    const apiUrl = new URL(`http://api:5000${apiPath}`);
    
    const response = await fetch(apiUrl, {
      method: req.method,
      headers: req.headers,
      body: req.body,
    });
    
    return new Response(response.body, {
      status: response.status,
      headers: response.headers,
    });
  }
};
  1. 修改Fresh组件中的fetch路径为相对路径:
import { useEffect, useState } from "preact/hooks";

export default function ApiFetch()  {
  const [data, setData] = useState(null);

  useEffect(() => {
    // 请求当前域名下的/api路径,由Fresh服务器转发到FastAPI
    fetch("/api/")
      .then(response => response.json())
      .then(data => setData(data));
  }, []);

  return <div>Hello from {data ? data.Hello : "still loading..."}</div>;
};

这样配置后,浏览器请求/api/会先发送到Fresh服务器,Fresh服务器在Docker内部网络中访问http://api:5000/并转发响应,既避免了硬编码服务器地址,又解决了网络访问问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:05:00