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

Docker Compose下Next Image客户端组件图片获取失败问题

解决Docker环境下Next.js Image组件无法获取API服务图片的问题

问题背景

  • Docker Compose配置了api和web服务,其余功能正常
  • 标记'use client'并通过dynamic禁用SSR后,next/image组件仍出现ECONNREFUSED的Fetch失败错误
  • 图片可在主机通过http://localhost:3000/uploads/sample/9.png访问,但容器内需用Docker服务名api替代localhost

错误日志

TypeError: fetch failed
web  |     at node:internal/deps/undici/undici:13178:13
web  |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
web  |     at async fetchExternalImage (/usr/src/app/node_modules/.pnpm/next@14.2.5_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.77.8/node_modules/next/dist/server/image-optimizer.js:580:17)
web  |     at async DevServer.imageOptimizer (/usr/src/app/node_modules/.pnpm/next@14.2.5_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.77.8/node_modules/next/dist/server/next-server.js:650:48)
web  |     at async cacheEntry.imageResponseCache.get.incrementalCache (/usr/src/app/node_modules/.pnpm/next@14.2.5_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.77.8/node_modules/next/dist/server/next-server.js:182:65)
web  |     at async /usr/src/app/node_modules/.pnpm/next@14.2.5_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.77.8/node_modules/next/dist/server/response-cache/index.js:90:36
web  |     at async /usr/src/app/node_modules/.pnpm/next@14.2.5_react-dom@18.3.1_react@18.3.1__react@18.3.1_sass@1.77.8/node_modules/next/dist/lib/batcher.js:45:32 {
web  |   [cause]: AggregateError [ECONNREFUSED]:
web  |       at internalConnectMultiple (node:net:1118:18)
web  |       at afterConnectMultiple (node:net:1685:7)
web  |       at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
web  |     code: 'ECONNREFUSED',
web  |     [errors]: [ [Error], [Error] ]
web  |   }
web  | }
web  |  GET /_next/image?url=http%3A%2F%2Flocalhost%3A3000%2Fuploads%2Fsample%2F9.png&w=1200&q=75 500 in 41ms
web  |  GET /_next/image?url=http%3A%2F%2Flocalhost%3A3000%2Fuploads%2Fsample%2F9.png&w=1200&q=75 500 in 29ms

相关代码

客户端Image组件

'use client'
import Image from "next/image";

type PostImgProps = {
  imgUrl: string;
};

const PostImg = (p: PostImgProps) => {
  return (
    <Image
      className="object-cover"
      src={p.imgUrl}
      alt="post image"
      width={1200}
      height={1000}
    />
  );
};

export default PostImg;

动态导入代码

const PostImg = dynamic(
  () => import('@/path/to/postImg'),
  {
    ssr: false,
    loading: () => (
      <div className="...">
        <!-- loader code -->
      </div>
    )
  }
);

解决方案

核心原因:即使禁用组件SSR,Next.js的图片优化器仍会在服务器端发起请求获取图片,因此需确保服务器端能通过Docker服务名访问API,客户端用主机地址访问。

方案1:环境变量区分地址 + 配置remotePatterns

  1. 在next.config.js中配置允许的图片源,兼容容器内和主机环境:
/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      // 容器内服务器端用api服务名访问
      {
        protocol: 'http',
        hostname: 'api',
        port: '3000',
        pathname: '/uploads/**',
      },
      // 客户端用localhost访问
      {
        protocol: 'http',
        hostname: 'localhost',
        port: '3000',
        pathname: '/uploads/**',
      },
    ],
  },
};

module.exports = nextConfig;
  1. 在传递图片地址时,根据环境替换域名:
// 示例:从API获取图片路径后替换域名
const rawImgPath = "/uploads/sample/9.png";
const imgUrl = process.env.NODE_ENV === 'production' 
  ? `http://api:3000${rawImgPath}` 
  : `http://localhost:3000${rawImgPath}`;

方案2:Next.js API代理(无需环境判断)

创建反向代理路由,让所有图片请求通过Web服务转发到API,避免域名差异问题:

  1. 创建app/api/proxy/[...path]/route.js:
import { NextResponse } from 'next/server';

export async function GET(request) {
  const path = request.nextUrl.pathname.replace('/api/proxy/', '');
  const apiUrl = `http://api:3000/${path}`;
  
  const response = await fetch(apiUrl);
  const blob = await response.blob();
  
  return new NextResponse(blob, {
    headers: {
      'Content-Type': response.headers.get('Content-Type'),
    },
  });
}
  1. 组件中使用代理路径:
<Image
  src={`/api/proxy/uploads/sample/9.png`}
  alt="post image"
  width={1200}
  height={1000}
/>

方案3:禁用Next.js图片优化(简单但失去优化功能)

如果不需要自动缩放、格式转换等优化,直接给Image组件添加unoptimized={true},图片将由客户端直接请求:

<Image
  className="object-cover"
  src={p.imgUrl}
  alt="post image"
  width={1200}
  height={1000}
  unoptimized={true}
/>

环境信息

  • Node.js: 20
  • Next.js: 14.2.5

内容的提问来源于stack exchange,提问作者Md. A. Apu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:53:18