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

Next.js 14添加Middleware后Public目录图片加载失败求助

问题修复:静态资源请求返回HTML异常

问题背景

原本代码运行正常,添加Middleware文件后出现异常:请求资源/public/icons/handshake_icon.png返回text/html; charset=utf-8,导致资源无效。

相关代码

src/middleware.ts

import { NextRequest, NextResponse } from 'next/server'

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
}

export default async function middleware(req: NextRequest) {
  const url = req.nextUrl

  // Get hostname of request (e.g. demo.vercel.pub, demo.localhost:3000)
  let hostname = req.headers
    .get('host')!
    .replace('.localhost:3000', `.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`)

  const searchParams = req.nextUrl.searchParams.toString()
  // Get the pathname of the request (e.g. /, /about, /blog/first-post)
  const path = `${url.pathname}${
    searchParams.length > 0 ? `?${searchParams}` : ''
  }`

  // rewrites for app pages
  if (hostname == `help.${process.env.NEXT_PUBLIC_ROOT_DOMAIN}`) {
    return NextResponse.rewrite(
      new URL(`/help${path === '' ? '' : path}`, req.url),
    )
  }

  // rewrite root application to `/` folder
  if (
    hostname === 'localhost:3000' ||
    hostname === process.env.NEXT_PUBLIC_ROOT_DOMAIN
  ) {
    return NextResponse.rewrite(new URL(`${path === '/' ? '' : path}`, req.url))
  }
}

src/app/help/component/Topic.tsx

import Image from 'next/image'
import React from 'react'

const Topic = () => {
  return (
    <div className="relative w-12 h-12 bg-slate-50">
      <Image
        src={'/public/icons/handshake_icon.png'}
        alt={props.topicName}
        fill={true}
      />
    </div>
  )
}

export default Topic

问题原因及修复方案

1. Image组件路径错误

Next.js的public目录是静态资源的根目录,引用资源时不需要添加/public前缀。当前路径/public/icons/handshake_icon.png会被Middleware拦截并重写,返回HTML内容而非静态图片。

修复:
修改Image组件的src属性,去掉/public前缀:

<Image
  src={'/icons/handshake_icon.png'}
  alt="握手图标" // 或补充props.topicName的定义
  fill={true}
/>

2. Middleware规则未排除静态资源路径

当前Middleware的matcher规则没有排除/public开头的路径,导致所有静态资源请求都被Middleware处理,触发重写逻辑返回HTML。

修复:
更新middleware.ts中的config.matcher,添加public到排除列表:

export const config = {
  matcher: [
    '/((?!api|_next/static|_next/image|favicon.ico|public).*)',
  ],
}

额外注意

组件中props.topicName未定义,建议补充组件的props参数,避免运行时错误:

interface TopicProps {
  topicName: string
}

const Topic = ({ topicName }: TopicProps) => {
  return (
    <div className="relative w-12 h-12 bg-slate-50">
      <Image
        src={'/icons/handshake_icon.png'}
        alt={topicName}
        fill={true}
      />
    </div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:43:12