π μ λ‘λ ν λ°μ°μ²μ ν¬κΈ° μ νμ μΆκ°ν μ μμκΉμ?
νΈλ¦¬ν TNA ννΈλμΉ μλ ννΈλκ° κ³ κ°μκ² μμ½ λ°μ°μ²λ₯Ό μ μ‘νλ κΈ°λ₯μ΄ μμ΅λλ€.
κΈ°μ‘΄μλ νμΌ μ¬μ΄μ¦μ μ ν μμ΄ μ μ‘νλλ‘ νλλ°, μ¬μ΄μ¦κ° μ»€μ§ κ²½μ° μ΄μκ° μ겨μ
μ΄λ²μ 리λ΄μΌνλ©΄μ μλ²μμ λ°μ°μ² μ¬μ΄μ¦κ° ν΄ κ²½μ° μ΄λ₯Ό λΆλ¦¬ν΄μ μ μ‘ μ²λ¦¬νλ κ² μ΄μΈμ
νλ‘ νΈμλμμλ κ°λ³ λ°μ°μ²μ μ©λ μ ν(15MB)μ μΆκ°νκΈ°λ‘ νμ΅λλ€.
μ΄λ₯Ό μν΄ λΈλΌμ°μ μμ μ¬λ¦¬λ νμΌ μ¬μ΄μ¦ μ²΄ν¬ μ΄μΈμλ
S3 μ μ΄λ―Έ μ λ‘λ λ λ°μ°μ² νμΌ μ¬μ΄μ¦λ₯Ό μ‘°νν΄μ
κ° λ°μ°μ² νλͺ©μ μ©λμ 보λ₯Ό ν¨κ» λ ΈμΆν΄μ€μΌ νμ΅λλ€.
κ·ΈλμΌ κ³ κ°μ΄ μ΄λ€ νμΌμ λ¬Έμ κ° μλμ§ νλ²μ νμΈμ΄ κ°λ₯ν ν λκΉμ.
π S3 νμΌ μ¬μ΄μ¦ (HeadObject)
λΈλΌμ°μ μμ μ λ‘λν νμΌ μ¬μ΄μ¦λ₯Ό μμμ€λ κ²μ λ³λ€λ₯Έ μ²λ¦¬κ° νμμμ§λ§,
μ΄λ―Έ S3 μ μ λ‘λν νμΌμ μμμ€κΈ° μν΄μλ S3 μ HeadObject μ κ·Όμ΄ νμν©λλ€.
HTTP μμ² μ€μμ HEAD λ request λμμ content λ©ν μ 보λ₯Ό μ»μ μ μλ μμ²μ λλ€.
S3 μμλ μ κ·Όν λμ νμΌμ HEAD μ 보λ₯Ό HeadObject λ₯Ό ν΅ν΄ μ 곡νκ³ μμ΅λλ€.
ννΈλμΉμ Next.js μ API Routes λ₯Ό μ΄μ©ν΄μ API νλ‘μλ₯Ό ꡬμ±νκ³ μκΈ° λλ¬Έμ
μ¬κΈ°μ νΈλ€λ¬λ₯Ό μΆκ°ν΄μ£Όλ λ°©ν₯μΌλ‘ μ§ννμ΅λλ€.
import { NextApiRequest, NextApiResponse } from 'next'
import { S3 } from 'aws-sdk' // β
aws-sdk v2 λ₯Ό μ¬μ©νκ³ μμ΅λλ€.
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const s3 = new S3({
... access key, id λ±λ± μ€μ κ°λ€
})
const { fileKey } = req.body
try {
const data = await s3
.headObject({
Bucket: S3_BUCKET,
Key: fileKey,
})
.promise()
res.status(200).send(data)
} catch (error) {
// ...
}
}
νμΌμ μμ²ν S3 κ°μ²΄λ₯Ό μμ±ν λ€μ, headObject μμ²μΌλ‘
response body κ° λΉμ΄μλ λ©ν μ 보λ₯Ό λ΄κ³ μλ μλ΅μ μ»μ μ μμ΅λλ€.
HTTP/1.1 200
Content-Length: ContentLength
ETag: ETag
Cache-Control: CacheControl
Content-Disposition: ContentDisposition
Content-Encoding: ContentEncoding
Content-Language: ContentLanguage
Content-Type: ContentType
Expires: Expires
// ...
λλ΅ μμ κ°μ νμμ κ°μ§λ μλ΅μ 보λ΄μ£Όλ©° μ¬κΈ°μ Content-Length λ₯Ό ν΅ν΄
νμΌμ ν¬κΈ°λ₯Ό Byte λ¨μλ‘ μ½μ΄μ¬ μ μμ΅λλ€.
HeadObject μμ²μ μμ²μ λν 400, 403, 404 3κ°μ§μ μλ¬ μΌμ΄μ€κ° μ‘΄μ¬ν©λλ€.
μ΄λ₯Ό μν΄ aws-sdk v3 λΆν°λ Error Class λ₯Ό μ μν΄μ μ 곡ν΄μ£Όμ§λ§,
v2 μμλ AWSError λΌλ μΈν°νμ΄μ€λ§ ꡬνλμ΄μκ³
μ€μ μλ¬ ν΄λμ€λ μ 곡ν΄μ£Όμ§ μκΈ° λλ¬Έμ error.name μμ±μΌλ‘ μλ¬ νμ μ ꡬλΆνλλ‘ νμ΅λλ€.
try { /** headObject μμ² */ }
catch (error) {
let errorCode = 'unknown'
if (error instanceof Error) {
errorCode = error.name
}
if (errorCode === 'BadRequest') {
res.status(400).send(error)
} else if (errorCode === 'Forbidden') {
res.status(403).send(error)
} else if (errorCode === 'NotFound') {
res.status(404).send(error)
} else {
res.status(500).send('Error From AWS SDK')
}
}
π λΈλΌμ°μ νμΌ μ¬μ΄μ¦ (file.size)
λΈλΌμ°μ μμ input νκ·Έλ‘ μ λ‘λλ νμΌμ μ¬μ΄μ¦λ
File κ°μ²΄μ size μμ±μΌλ‘ μ κ·Όμ΄ κ°λ₯ν©λλ€.
μ¬κΈ°λ λ§μ°¬κ°μ§λ‘ Byte λ¨μλ‘ λ°νν΄μ€λλ€.
const handleChange = (files: FileList) => {
const sizes = [...files].map((file) => file.size) // β
File.size μμ±μΌλ‘ μ κ·Ό
// ...
}
<input type="file" onChange={handleChange} />
π Byte νμ λ³ν
μλ§λ Byte λ¨μλ‘ νκΈ°λ ν¬κΈ°λ₯Ό λ± λ³΄κ³ μ, μ΄ νμΌμ΄ xxMB μ¬μ λ¬Έμ κ° μ긴거ꡬλ? λΌλ©°
νλ²μ μλ³ν μ μλ μ¬λμ μμ κ²λλ€.
μ΄λ₯Ό μν΄ μ¬λμ΄ μ΄ν΄νκΈ° μ¬μ΄ λ¨μλ‘ λ³νμ ν΄μ 보μ¬μ€μΌνλλ°,
μ¬κΈ°μ μ¬μ©ν Byte λ¨μ ν¬λ§·ν ν¨μλ₯Ό ꡬνν΄μ€λλ€.
π‘ Note
μ€μ μ½λμμλ symbol λ ΈμΆ μ¬λΆ, μμμ μ리μ λ±μ ν¨μμ μΈμλ‘ λ°μμ μ²λ¦¬νμ§λ§,
μ¬κΈ°μλ μμλ₯Ό μν΄ κ°λ΅ννμμ΅λλ€.
function convertByte(value: number) {
const kb = 1024
const fraction = 2
const notations = ['Byte', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const exponent = Math.floor(Math.log(value) / Math.log(kb))
const size = parseFloat((value / Math.pow(kb, exponent)).toFixed(frac))
const notation = notations[exponent]
return `${size} ${notation}`
}
μ μ ν ν μ€νΈ μ½λλ μΆκ°ν΄μ μ λλ‘ λ³νμ΄ λλμ§ νμΈν΄λ΄ λλ€.
describe('Formatter > byte', () => {
it('should change 1024byte to 1KB', () => {
expect(Formatter.byte({ value: 1024 })).toBe('1 KB')
})
it('should change 10000byte to 9.77KB', () => {
expect(Formatter.byte({ value: 10000 })).toBe('9.77 KB')
})
it('should change 100000000byte to 95.37MB', () => {
expect(Formatter.byte({ value: 100000000 })).toBe('95.37 MB')
})
it('should change 100000000000byte to 93.13GB', () => {
expect(Formatter.byte({ value: 100000000000 })).toBe('93.13 GB')
})
})
π‘ 1K = 1000? 1024?
μ΄λ²μ μκ²λ μ¬μ€μΈλ°, 2μ§λ² μ»΄ν¨ν μμ€ν μμλ 1MB = 1024Byte μ΄κΈ° λλ¬Έμ
10μ§λ²μ μ¬μ©νλ νκ²½μμ 보νΈμ μΌλ‘ μ¬μ©λλ 1K = 1000 μ μ°¨μ΄κ° μλ€κ³ ν©λλ€.
λλ¬Έμ λ³΄ν΅ κΈ°κΈ° μ€νμ λͺ μλ νλμ¨μ΄ μ©λλ³΄λ€ μ€μ μ¬μ΄μ¦λ μκ² νκΈ°λλ€κ³ νλ€μ.
π κ²μ¦ λ‘μ§ μΆκ°νκΈ°
μ΄μ μμμ ꡬνν ν¨μλ€μ μ΄μ©ν΄μ λ°μ°μ² νμΌμ μ λ‘λ νκΈ° μ μ
νμΌ μ¬μ΄μ¦ 체ν¬λ₯Ό ν΄μ£Όλλ‘ κ²μ¦ κ³Όμ μ μΆκ°ν©λλ€.
// νμ¬ μ»΄ν¬λνΈμ stateμ νμΌ λͺ©λ‘μ΄ File[] ννλ‘ κ΄λ¦¬λκ³ μλ€λ κ°μ
const handleVoucherUpload = (files: File[]) => {
const limit = 1024 * 1024 * 15 // 15MB
const exceed = stagedFiles.some((file) => file.size > limit)
if (exceed) {
throw new Error('FileSizeLimitExceed')
}
}
ν΄λΉ ν¨μλ₯Ό νΈμΆνλ μͺ½μμ μλ¬ νμ μ 체ν¬ν΄μ FileSizeLimitExceed μΌ κ²½μ°μλ
μλ΄ λ©μμ§λ₯Ό λ΄μ ν μ€νΈ λ©μμ§λ₯Ό λμμ€λλ€.
π μ°Έκ³ μλ£
where to find all the exception classes in AWS-SDK for dynamodb in NodeJS typescript?
'π¨βπ» web.dev > fe' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
νλ‘ νΈμλ E2E ν μ€ν (with Cypress) (2) | 2023.03.19 |
---|---|
Next.js styled-component μ€μ νκΈ° (SSR FOUC μ΄μ) (0) | 2022.11.27 |
React μ΄λ²€νΈ μ²λ¦¬λ°©μκ³Ό SyntheticEvent (0) | 2022.10.17 |
File API λ₯Ό μ΄μ©ν Input μ»΄ν¬λνΈ λ§λ€κΈ° (2) | 2022.08.13 |
Next.js API Routes μμ보기 (2) | 2022.07.26 |
π¬ λκΈ