Skip to content

Commit 7304d26

Browse files
committed
fix: 이미지 컴포넌트에서 잘못된 로드 시 오류 해결
1 parent b331a6e commit 7304d26

File tree

4 files changed

+100
-11
lines changed

4 files changed

+100
-11
lines changed

components/ImageSafe.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import getConfig from "next/config";
2+
import Image from "next/image";
3+
import { useState, useEffect } from "react";
4+
5+
const IMAGE_PLACEHOLDER = "/images/landscape-placeholder.svg";
6+
7+
export default function ImageSafe({ src, alt }: { src: string; alt: string }) {
8+
const [imageSrc, setImageSrc] = useState<string | null>(null);
9+
10+
useEffect(() => {
11+
const checkImageConfig = async () => {
12+
try {
13+
const res = await fetch(
14+
"/api/check-image?url=" + encodeURIComponent(src)
15+
);
16+
console.log(res);
17+
if (res.ok) {
18+
setImageSrc(src);
19+
} else {
20+
console.error("Image source not configured in next.config.js");
21+
console.log(res);
22+
setImageSrc(IMAGE_PLACEHOLDER);
23+
}
24+
} catch (error) {
25+
console.error("Error checking image configuration:", error);
26+
setImageSrc(IMAGE_PLACEHOLDER);
27+
}
28+
};
29+
30+
checkImageConfig();
31+
}, [src]);
32+
33+
if (!imageSrc) {
34+
return null; // 또는 로딩 표시기
35+
}
36+
37+
return (
38+
<Image
39+
fill
40+
src={imageSrc}
41+
alt={alt}
42+
style={{
43+
objectFit: "cover",
44+
}}
45+
/>
46+
);
47+
}

components/PostBoard.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { Article, ArticleList } from "@/types/Article.type";
22
import Image from "next/image";
33
import styles from "./PostBoard.module.css";
4-
import { useEffect, useRef, useState } from "react";
4+
import { Suspense, useEffect, useRef, useState } from "react";
55
import {
66
getArticleList,
77
GetArticleListParams,
88
OrderBy,
99
} from "@/api/article.api";
1010
import formatDate from "../lib/formatDate";
1111
import { useDeviceType } from "@/contexts/DeviceTypeContext";
12+
import ImageSafe from "./ImageSafe";
1213

1314
const DEFAULT_PARAMS: GetArticleListParams = {
1415
page: 1,
@@ -143,22 +144,13 @@ export default function PostBoard({
143144

144145
function PostItem({ article }: { article: Article }) {
145146
const createdAt = formatDate(article.createdAt);
146-
const [imgSrc, setImgSrc] = useState(article.image || IMAGE_PLACEHOLDER);
147147

148148
return (
149149
<div className={styles.Item}>
150150
<div className={styles.ItemContent}>
151151
<h3 className={styles.ItemTitle}> {article.title}</h3>
152152
<div className={styles.ItemPreview}>
153-
<Image
154-
fill
155-
src={imgSrc}
156-
alt={article.title}
157-
style={{
158-
objectFit: "cover",
159-
}}
160-
onError={() => setImgSrc(IMAGE_PLACEHOLDER)}
161-
/>
153+
<ImageSafe src={article.image} alt={article.title} />
162154
</div>
163155
</div>
164156
<div className={styles.ItemInfo}>

next.config.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ const nextConfig = {
1111
},
1212
],
1313
},
14+
publicRuntimeConfig: {
15+
images: {
16+
remotePatterns: [
17+
{
18+
protocol: "https",
19+
hostname: "sprint-fe-project.s3.ap-northeast-2.amazonaws.com",
20+
port: "",
21+
pathname: "/**",
22+
},
23+
],
24+
},
25+
},
1426
};
1527

1628
module.exports = nextConfig;

pages/api/check-image.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import getConfig from "next/config";
2+
3+
export default async function handler(req, res) {
4+
const { url } = req.query;
5+
const {
6+
publicRuntimeConfig: {
7+
images: { remotePatterns },
8+
},
9+
} = getConfig();
10+
11+
try {
12+
const imageRes = await fetch(url);
13+
14+
if (imageRes.status === 200) {
15+
const isValid = remotePatterns.some((pattern) => {
16+
const srcUrl = new URL(url);
17+
const validProtocol = srcUrl.protocol.slice(0, -1) === pattern.protocol;
18+
const validHost = srcUrl.hostname === pattern.hostname;
19+
return validProtocol && validHost;
20+
});
21+
22+
if (isValid) {
23+
res.status(200).json({ imgSrc: url });
24+
} else {
25+
res.status(403).json({
26+
message: "Image source not configured in next.config.js",
27+
});
28+
}
29+
} else {
30+
res.status(400).json({
31+
message: "URL does not point to a valid image",
32+
});
33+
}
34+
} catch (error) {
35+
console.error("Error checking image:", error);
36+
res.status(500).json({ imessage: "Error checking image" });
37+
}
38+
}

0 commit comments

Comments
 (0)