Next.js 13 无法显示Strapi 4.6中存储的图片问题求助
Strapi 4.6 + Next.js 13 图片加载失败问题解决
问题现象
使用Strapi 4.6作为后端、Next.js 13作为前端开发应用时,电影的标题、年份和描述可正常显示,但图片无法加载,服务器返回错误:
The requested resource isn't a valid image for /uploads/2008_Jaden_3c49c0fe45.jpg received text/html; charset=utf-8
相关代码与配置
页面组件代码
export default function Page({ params }) { let movie = use(getMovie(params.movieID)); console.log("Movie This is the text", movie); return ( <div> <p className="text-3xl">{movie.data.attributes.title}</p> <p className="mt-2">Year: {movie.data.attributes.year}</p> <p className="mt-2">Description: {movie.data.attributes.description}</p> <Image className='mt-2' src={movie.data.attributes.image.data.attributes.url} alt={movie.data.attributes.title} width={500} height={349} /> </div> ); }
服务器报错信息
event - compiled client and server successfully in 145 ms (545 modules) The requested resource isn't a valid image for /uploads/2008_Jaden_3c49c0fe45.jpg received text/html; charset=utf-8
next.config.js 配置
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { appDir: true, }, images: { remotePatterns: [ { protocol: "http", hostname: "127.0.0.1", port: "1337", pathname: "/**", }, ], }, }; module.exports = nextConfig;
Strapi 返回的 API 数据
// 20230217152302 // http://127.0.0.1:1337/api/movies?populate=* { "data": [ { "id": 1, "attributes": { "createdAt": "2023-02-03T15:39:55.796Z", "updatedAt": "2023-02-07T11:39:47.652Z", "publishedAt": "2023-02-03T15:40:08.569Z", "title": "Lord of the Rings", "year": 2001, "description": "A meek Hobbit from the Shire and eight companions set out on a journey to destroy the powerful One Ring and save Middle-earth from the Dark Lord Sauron", "slug": "lord-of-the-rings", "image": { "data": { "id": 3, "attributes": { "name": "6FDUBGB.jpg", "alternativeText": null, "caption": null, "width": 2000, "height": 2496, "formats": { "thumbnail": { "name": "thumbnail_6FDUBGB.jpg", "hash": "thumbnail_6_FDUBGB_f8b45dbbae", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 125, "height": 156, "size": 8.49, "url": "/uploads/thumbnail_6_FDUBGB_f8b45dbbae.jpg" }, "small": { "name": "small_6FDUBGB.jpg", "hash": "small_6_FDUBGB_f8b45dbbae", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 401, "height": 500, "size": 62.75, "url": "/uploads/small_6_FDUBGB_f8b45dbbae.jpg" }, "medium": { "name": "medium_6FDUBGB.jpg", "hash": "medium_6_FDUBGB_f8b45dbbae", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 601, "height": 750, "size": 117.55, "url": "/uploads/medium_6_FDUBGB_f8b45dbbae.jpg" }, "large": { "name": "large_6FDUBGB.jpg", "hash": "large_6_FDUBGB_f8b45dbbae", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 801, "height": 1000, "size": 182.81, "url": "/uploads/large_6_FDUBGB_f8b45dbbae.jpg" } }, "hash": "6_FDUBGB_f8b45dbbae", "ext": ".jpg", "mime": "image/jpeg", "size": 597.08, "url": "/uploads/6_FDUBGB_f8b45dbbae.jpg", "previewUrl": null, "provider": "local", "provider_metadata": null, "createdAt": "2023-02-07T11:39:40.120Z", "updatedAt": "2023-02-07T11:39:40.120Z" } } } } }, { "id": 2, "attributes": { "createdAt": "2023-02-03T15:42:51.349Z", "updatedAt": "2023-02-07T11:40:12.979Z", "publishedAt": "2023-02-03T15:42:52.112Z", "title": "Star Wars", "year": 1977, "description": "Luke Skywalker joins forces with a Jedi Knight, a cocky pilot, a Wookiee and two droide to save the galaxy from the Empire's wold-destroying battle station, while also attemting te rescue Princess Leia from the mysterious Darth Vader.", "slug": "star-wars", "image": { "data": { "id": 4, "attributes": { "name": "2008 Jaden.jpg", "alternativeText": null, "caption": null, "width": 1868, "height": 1304, "formats": { "thumbnail": { "name": "thumbnail_2008 Jaden.jpg", "hash": "thumbnail_2008_Jaden_3c49c0fe45", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 223, "height": 156, "size": 9.92, "url": "/uploads/thumbnail_2008_Jaden_3c49c0fe45.jpg" }, "small": { "name": "small_2008 Jaden.jpg", "hash": "small_2008_Jaden_3c49c0fe45", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 500, "height": 349, "size": 35.21, "url": "/uploads/small_2008_Jaden_3c49c0fe45.jpg" }, "medium": { "name": "medium_2008 Jaden.jpg", "hash": "medium_2008_Jaden_3c49c0fe45", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 750, "height": 524, "size": 65.83, "url": "/uploads/medium_2008_Jaden_3c49c0fe45.jpg" }, "large": { "name": "large_2008 Jaden.jpg", "hash": "large_2008_Jaden_3c49c0fe45", "ext": ".jpg", "mime": "image/jpeg", "path": null, "width": 1000, "height": 698, "size": 102.08, "url": "/uploads/large_2008_Jaden_3c49c0fe45.jpg" } }, "hash": "2008_Jaden_3c49c0fe45", "ext": ".jpg", "mime": "image/jpeg", "size": 258.7, "url": "/uploads/2008_Jaden_3c49c0fe45.jpg", "previewUrl": null, "provider": "local", "provider_metadata": null, "createdAt": "2023-02-07T11:40:06.583Z", "updatedAt": "2023-02-07T11:40:06.583Z" } } } } } ], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 2 } } }
问题原因
Strapi返回的图片URL是相对路径(如/uploads/2008_Jaden_3c49c0fe45.jpg),Next.js的Image组件会将其当作前端本地资源路径去请求,而非Strapi服务器的资源地址,导致请求返回的是前端的404 HTML页面,因此报错“不是有效图片”。
解决方法
方法一:前端拼接完整图片URL
在页面组件中,将Strapi的基础地址与图片相对URL拼接,生成完整的资源地址:
export default function Page({ params }) { const movie = use(getMovie(params.movieID)); const strapiBaseUrl = "http://127.0.0.1:1337"; // 拼接完整图片URL const imageUrl = `${strapiBaseUrl}${movie.data.attributes.image.data.attributes.url}`; return ( <div> <p className="text-3xl">{movie.data.attributes.title}</p> <p className="mt-2">Year: {movie.data.attributes.year}</p> <p className="mt-2">Description: {movie.data.attributes.description}</p> <Image className='mt-2' src={imageUrl} alt={movie.data.attributes.title} width={500} height={349} /> </div> ); }
方法二:配置Strapi返回完整图片URL
修改Strapi项目的config/server.js,添加url配置,让API返回的图片URL直接包含完整的服务器地址:
module.exports = ({ env }) => ({ host: env('HOST', '0.0.0.0'), port: env.int('PORT', 1337), app: { keys: env.array('APP_KEYS'), }, // 添加这一行,设置Strapi的公开访问地址 url: env('PUBLIC_URL', 'http://127.0.0.1:1337'), });
配置完成后重启Strapi,此时API返回的image.url会是完整的http://127.0.0.1:1337/uploads/xxx.jpg,前端无需拼接可直接使用。
内容的提问来源于stack exchange,提问作者RobB
相关产品推荐
相关产品推荐

