write - page 파일
"use client"
import { useState } from "react";
const Write = () => {
let [src, setSrc] = useState('')
const imgGet = async(e:any) =>{
let file = e.target.files[0] // 업로드한 파일.
const filename = encodeURIComponent(file.name) //file.name은 파일 이름이다. encodeURIComponent은 한글이름은 깨질수가있어서 사용하는코드
console.log(filename)
let res = await fetch(`/api/post/image?file=${filename}`) // 파일을 쿼리형식으로 보낸다.
res = await res.json() //json 데이터이기 때문에 json 변환시켜야한다.
//S3 업로드
const formData = new FormData()
Object.entries({ ...res.fields , file }).forEach(([key, value]:any) => {
formData.append(key, value)
})
let 업로드결과 = await fetch(res.url, {
method: 'POST',
body: formData,
})
console.log(업로드결과)
if (업로드결과.ok) {
setSrc(업로드결과.url + '/' + filename)
} else {
console.log('실패')
}
}
//로그인 데이터 가져오기 getServerSession(authOptions) /getServerSession 는 로그인 데이터가져오기 함수
//authOptions 는 만들어둔 파일 에서 가져와야함. //삭제함.
// interface Session {
// user: {
// name: string;
// email: string;
// image: string;
// };
// }
// let session:Session | null = await getServerSession()
//console.log(session)
return (
<div className='p-20'>
<h4>글작성</h4>
<form action="/api/test" method="POST">
<button type="submit">버튼</button>
</form>
<form action="/api/post/new" method="POST">
<input name="title" placeholder='제목'></input>
<input name="content" placeholder='내용'></input>
<button type="submit">Post 버튼</button>
</form>
<input type="file" accept="image/*" onChange={imgGet}/>
<img src={src} alt="미리보기 이미지"/>
<form action="/api/time" method="GET">
<button type="submit">시간버튼</button>
</form>
<form action="/api/list" method="POST">
<input name="title" />
<button type="submit">list 버튼</button>
</form>
</div>
);
};
export default Write;
현재 fields 쪽 빨간밑줄이 쳐진다.. 왜이러지? 이미지업로드는 좀더 공부필요해보임.
하지만 파일올리기로 바로선택하자마자 서버에 저장되기때문에
https://velog.io/@jiwonyyy/createObjectURL을-사용해서-이미지-업로드-후-미리보기
createObjectURL을 사용해서 이미지 업로드 후 미리보기
대부분의 서비스에서는 이미지 업로드 시, 내가 올린 사진이 어떤 사진인지 미리 확인할 수 있는 "미리보기" 단계를 거친 후에 이미지를 업로드 하는 기능을 제공하고 있다.
velog.io
https://kyounghwan01.github.io/blog/JS/JSbasic/Blob-url/#createobjecturl
image Blob 객체를 url로 바꾸어 img 띄우기, javascript, JavaScript, blob, createObjectUrl, revokeObjectUrl, react, vue,
image Blob 객체를 url로 바꾸어 img 띄우기, javascript, JavaScript, blob, createObjectUrl, revokeObjectUrl, react, vue, window, document
kyounghwan01.github.io
[React/JavaScript] 이미지 파일 업로드 전 미리 보는 방법
이미지 file을 서버에 업로드하기 전, 등록한 파일을 화면에서 미리 보여주고 싶을 때가 있다. URL.createObjectURL() 이용하기 부제: 이미지 미리 보기 url 생성 거두절미하고 리액트 코드부터 보시죠...
xively.tistory.com
위정보를 참고하면 서버에 업로드 하지않고 미리보기할수있는방법
이미지 업로드기능을 만들어봅시다.
Presigned URL 방식으로 유저 -> S3 이렇게 직접 이미지 업로드를 시키면 좋다고 했는데

▲ 이런 식으로 코드짜면 됩니다.
글로 적어보면
1. 글작성 페이지의 <input>에서 유저가 이미지 고르는 순간 서버에게 Presigned URL 달라고 GET요청을 합니다.
심심하니까 이미지 이름도 같이 보내줌
2. 그럼 서버는 괜찮은 유저인지 이거저거 검사해보고 Presigned URL을 만들어서 유저 브라우저로 보내줌
3. 유저는 브라우저에서 Presigned URL을 이용해서 S3로 이미지를 보냅니다.
4. 성공시 업로드된 이미지의 URL을 <img src=" ">에 박아서 이미지 업로드된걸 보여줌
이런 식으로 코드짜면 되는데 이걸 어떻게 알았냐고요?
실은 next.js 공식예제로 나와있어서 그거 그대로 카피하면 됩니다.
1. 서버야 Presigned URL 줘
(/write/page.js)
'use client'
export default function Write(){
return (
<div className="p-20">
<h4>글작성</h4>
<form action="/api/post/new" method="POST">
<input name="title" placeholder="글제목"/>
<input name="content" placeholder="글내용"/>
<button type="submit">전송</button>
</form>
<input type="file" accept="image/*" onChange={
async (e)=>{
let file = e.target.files[0]
let filename = encodeURIComponent(file.name)
let res = await fetch('/api/post/image?file=' + filename)
res = await res.json()
}
} />
<img />
</div>
)
}
1. 이미지 선택용 <input>과 그걸 보여줄 <img>를 만들었습니다.
2. onChange안에 파일선택시 파일이름을 가져오고
3. 서버로 Presigned URL좀 달라고 GET요청을 합니다. 심심하니까 파일이름도 보냄
그럼 Presigned URL 발급해주는 서버기능을 만들어봅시다.
2. 서버는 Presigned URL 발급해서 보내주기
(/api/post/image.js)
import aws from 'aws-sdk'
export default async function handler(요청, 응답){
aws.config.update({
accessKeyId: process.env.ACCESS_KEY,
secretAccessKey: process.env.SECRET_KEY,
region: 'ap-northeast-2',
signatureVersion: 'v4',
})
const s3 = new aws.S3();
const url = await s3.createPresignedPost({
Bucket: process.env.BUCKET_NAME,
Fields: { key : 요청.query.file },
Expires: 60, // seconds
Conditions: [
['content-length-range', 0, 1048576], //파일용량 1MB 까지 제한
],
})
응답.status(200).json(url)
}
1. npm install aws-sdk 해서 AWS 다룰 수 있는 라이브러리 하나 설치합시다.
2. aws.config.update 안에 님들 정보 채워주면 됩니다.
정보는 직접 기입하는거보다 .env 파일을 이용했는데
ACCESS_KEY=액세스키어쩌구
SECRET_KEY=액세스키시크릿
BUCKET_NAME=님들버킷명
님들 프로젝트 루트경로에 .env 파일을 하나 만들어서
위와 같이 채워주면 사용가능합니다.
3. createPresignedPost 함수 이용하면 PresignedURL을 발급해줍니다.
key : 옆에 유저가 보낸 파일이름 기입해주면 됩니다.
업로드가능한 최대용량, 제한시간 설정도 가능합니다.
3. S3로 업로드하기
(/write/page.js)
'use client'
import { useState } from "react";
export default function Write(){
let [src, setSrc] = useState('')
return (
<div className="p-20">
<h4>글작성</h4>
<form action="/api/post/new" method="POST">
<input name="title" placeholder="글제목"/>
<input name="content" placeholder="글내용"/>
<button type="submit">전송</button>
</form>
<input type="file" accept="image/*" onChange={
async (e) => {
let file = e.target.files[0]
let filename = encodeURIComponent(file.name)
let res = await fetch('/api/post/image?file=' + filename)
res = await res.json()
//S3 업로드
const formData = new FormData()
Object.entries({ ...res.fields, file }).forEach(([key, value]) => {
formData.append(key, value)
})
let 업로드결과 = await fetch(res.url, {
method: 'POST',
body: formData,
})
console.log(업로드결과)
if (업로드결과.ok) {
setSrc(업로드결과.url + '/' + filename)
} else {
console.log('실패')
}
}
} />
<img src={src} />
</div>
)
}
1. 어딘가로 폼데이터 전송시 <form>쓰는게 귀찮으면 new formData()를 쓰고 거기에 폼데이터들을 넣으면 됩니다.
2. 서버에서 받아온 res라는 변수 안에 숨어있던 데이터들과 이미지를 formData안에 넣고
3. res.url 경로로 전송하면 됩니다. 그럼 S3에 이미지 올라감
4. 업로드결과.url 뒤에 /파일이름만 붙이면 그게 님들 방금 업로드한 이미지 경로입니다.
이미지 경로를 <img src=""> 안에 넣거나 맘대로 하면 됩니다.
실은 이런 라이브러리 사용법은 공부하고 그럴 필요 없이 그냥 복사붙여넣기 해서 쓰면 잘쓰는 것입니다.
아무튼 이제 <input>에서 이미지를 선택하는 순간 이미지가 페이지에 보이는군요.
이제 글발행할 때 이미지 URL도 함께 DB에 저장해두면 필요한 페이지에서 보여줄 수 있지 않을까요
그건 여러분들이 직접 해봅시다.
- client component라서 글발행시 ajax요청으로 폼전송하는게 어떨까요
- 글의 상세페이지에선 글과 함께 업로드한 사진도 보여야합니다.
Q. 유저가 글발행 안하고 뒤로가기 누르면 S3 저장용량 낭비아님?
- 지금은 선택과 동시에 이미지를 업로드하고 있는데 글발행 누르면 이미지 업로드시키면 되겠군요.
업로드 전에 유저가 선택한 이미지 보여주려면 createObjectURL을 씁시다.
(참고) 이미지 업로드 잘되는지 확인 후에
AWS S3 콘솔에서 버킷의 권한설정 하던거 들어가서

▲ 이런거 체크해두는게 좋을 수도 있습니다.
왜냐면 지금 버킷정책 (Bucket policy) 으로 권한을 설정하고 있는데
ACL이라는 것으로도 권한을 설정할 수 있습니다.
두개의 권한이 겹치는 경우 최대한 느슨한 쪽으로 결정되기 때문에 ACL은 안쓰면 저렇게 차단해두는게 안전할 수 있습니다.
'임의의 ACL로 부여된 액세스 차단' 이라고 되어있는데
쉽게 말하면 '모든 ACL로 부여된 액세스를 차단하겠다'는 뜻입니다.
물론 이상한거 건드려서 뭔가 안되면 체크해제합시다.
'Next' 카테고리의 다른 글
Next13 미들웨어 사용법. (0) | 2023.08.07 |
---|---|
next13 다크모드 만들기. (0) | 2023.08.03 |
aws 이미지 업로드 하드만들기 1 [설정] (0) | 2023.07.31 |
aws 배포하기 [공부용] (0) | 2023.07.31 |
Next.13 로딩/에러/404 페이지 만들기 (0) | 2023.07.25 |