JavaScript์์ Base64 ์ธ์ฝ๋ฉ/๋์ฝ๋ฉ: btoa(), atob() ๋ฐ ์ ๋์ฝ๋
JavaScript์์ Base64 ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ
JavaScript๋ Base64 ๋ฌธ์์ด์ ์ธ์ฝ๋ฉํ๊ณ ๋์ฝ๋ฉํ๋ ์ฌ๋ฌ ๊ฐ์ง ๋ด์ฅ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ Node.js ์๋ฒ๋ฅผ ๊ตฌ์ถํ๋ , JSON, HTML, URL๊ณผ ๊ฐ์ ํ ์คํธ ๊ธฐ๋ฐ ํ์์์ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด Base64 ์์ ๋ฐฉ๋ฒ์ ์ดํดํ๋ ๊ฒ์ด ํ์์ ์ ๋๋ค.
๋ธ๋ผ์ฐ์ ์์ btoa() ๋ฐ atob() ์ฌ์ฉํ๊ธฐ
๋ธ๋ผ์ฐ์ JavaScript์์ Base64๋ฅผ ์ํ ๋ ๊ฐ์ง ํต์ฌ ํจ์๋ btoa()์ atob()์
๋๋ค. ์ด ํจ์ ์ด๋ฆ์ ์ค๋๋ ๋ช
๋ช
๊ท์น์ ๋ฐ๋ฆ
๋๋ค. btoa๋ "binary to ASCII"๋ฅผ, atob์ "ASCII to binary"๋ฅผ ์๋ฏธํฉ๋๋ค. ์ด ํจ์๋ค์ ์์ญ ๋
๋์ ๋ชจ๋ ์ฃผ์ ๋ธ๋ผ์ฐ์ ์์ ์ง์๋์ด ์์ต๋๋ค.
btoa()๋ก ์ธ์ฝ๋ฉํ๊ธฐ
const originalString = 'Hello, world!';
const encoded = btoa(originalString);
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ==
atob()๋ก ๋์ฝ๋ฉํ๊ธฐ
const base64String = 'SGVsbG8sIHdvcmxkIQ==';
const decoded = atob(base64String);
console.log(decoded);
// Output: Hello, world!
๋ ํจ์ ๋ชจ๋ Latin-1 ๋ฌธ์(๊ฐ ๋ฌธ์๊ฐ ๋จ์ผ ๋ฐ์ดํธ๋ก ํํ๋จ)๋ง ํฌํจ๋ ๋ฌธ์์ด์์ ์๋ํฉ๋๋ค. ์ด๋ ๋ค์์ ๋ค๋ฃฐ ์ค์ํ ์ ํ ์ฌํญ์ ๋๋ค.
์ ๋์ฝ๋ ๋ฐ ๋นASCII ๋ฌธ์ ์ฒ๋ฆฌํ๊ธฐ
ํํ ํจ์ : btoa()๋ ์ด๋ชจ์ง, ํ์, ์
์ผํธ ๋ฌธ์ ๋ฑ Latin-1 ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๋ฌธ์๊ฐ ํฌํจ๋ ๋ฌธ์์ด์ ๋ฐ์ผ๋ฉด ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค.
btoa('Hello ไฝ ๅฅฝ');
// Error: The string to be encoded contains characters outside of the Latin-1 range.
์ ๋์ฝ๋ ๋ฌธ์์ด์ ์ธ์ฝ๋ฉํ๋ ค๋ฉด ๋จผ์ ๋ฌธ์์ด์ ๋ฐ์ดํธ๋ก ๋ณํํ ๋ค์ ํด๋น ๋ฐ์ดํธ๋ฅผ ์ธ์ฝ๋ฉํด์ผ ํฉ๋๋ค. ํ๋์ ์ธ ์ ๊ทผ ๋ฐฉ์์ TextEncoder ๋ฐ TextDecoder API๋ฅผ ์ฌ์ฉํฉ๋๋ค:
function unicodeToBase64(str) {
const bytes = new TextEncoder().encode(str);
const binaryString = String.fromCharCode(...bytes);
return btoa(binaryString);
}
function base64ToUnicode(base64) {
const binaryString = atob(base64);
const bytes = Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
// Usage
const encoded = unicodeToBase64('Hello ไฝ ๅฅฝ ๐');
console.log(encoded);
// Output: SGVsbG8g5L2g5aW9IPCfj4A=
const decoded = base64ToUnicode(encoded);
console.log(decoded);
// Output: Hello ไฝ ๅฅฝ ๐
๊ตฌ์ ๊ธฐ๋ฒ์ผ๋ก encodeURIComponent์ decodeURIComponent๋ฅผ ์ฌ์ฉํ ์๋ ์์ง๋ง, TextEncoder/TextDecoder ์ ๊ทผ ๋ฐฉ์์ด ๋ ๊ฒฌ๊ณ ํ๋ฉฐ ๊ถ์ฅ๋๋ ํ๋์ ์ธ ์๋ฃจ์
์
๋๋ค.
์ด์ง ๋ฐ์ดํฐ(ArrayBuffer) ์ธ์ฝ๋ฉํ๊ธฐ
ํ์ผ, ์ด๋ฏธ์ง, ๋๋ fetch๋ FileReader์ ๊ฐ์ API์์ ๊ฐ์ ธ์จ ์์ ์ด์ง ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ๋๋ ์ผ๋ฐ์ ์ผ๋ก ArrayBuffer ๋๋ Uint8Array๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ด๋ฅผ Base64๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binaryString = '';
for (let i = 0; i < bytes.length; i++) {
binaryString += String.fromCharCode(bytes[i]);
}
return btoa(binaryString);
}
function base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
๋ธ๋ผ์ฐ์ ์์ ํ์ผ์ Base64๋ก ๋ณํํ๊ธฐ
๋ค์์ FileReader๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์๊ฐ ์ ํํ ํ์ผ์ Base64 ๋ฐ์ดํฐ URL๋ก ๋ณํํ๋ ์์ ํ ์์ ์
๋๋ค:
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsDataURL(file);
});
}
// Usage with a file input
document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
const file = e.target.files[0];
try {
const dataUrl = await fileToBase64(file);
console.log(dataUrl); // data:image/png;base64,iVBORw0KGgo...
} catch (err) {
console.error('Conversion failed:', err);
}
});
Node.js์์ Base64 ์ฌ์ฉํ๊ธฐ
Node.js๋ Base64 ์์
์ ์ํ Buffer ํด๋์ค๋ฅผ ์ ๊ณตํ๋ฉฐ, ์ด๋ ๋ธ๋ผ์ฐ์ ์ btoa/atob๋ณด๋ค ๋ ์ ์ฐํฉ๋๋ค. Buffer ํด๋์ค๋ ์ ๋์ฝ๋๋ฅผ ํฌํจํ ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ฉฐ, ์ฌ๋ฌ ์ธ์ฝ๋ฉ ํ์์ ์ง์ํฉ๋๋ค.
๊ธฐ๋ณธ ์ธ์ฝ๋ฉ ๋ฐ ๋์ฝ๋ฉ
// Encode a string to Base64
const encoded = Buffer.from('Hello, world!').toString('base64');
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ==
// Decode a Base64 string back to text
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
console.log(decoded);
// Output: Hello, world!
Node.js์์ ์ ๋์ฝ๋ ์ง์
๋ธ๋ผ์ฐ์ ์ btoa()์ ๋ฌ๋ฆฌ, Node.js Buffer๋ ์ ๋์ฝ๋๋ฅผ ์ํํ๊ฒ ์ฒ๋ฆฌํฉ๋๋ค:
const encoded = Buffer.from('Hello ไฝ ๅฅฝ ๐').toString('base64');
console.log(encoded);
// Output: SGVsbG8g5L2g5aW9IPCfj4A=
const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
console.log(decoded);
// Output: Hello ไฝ ๅฅฝ ๐
ํ์ผ์ ์ฝ์ด Base64๋ก ์ธ์ฝ๋ฉํ๊ธฐ
const fs = require('fs');
// Read a file and encode it to Base64
const buffer = fs.readFileSync('image.png');
const base64 = buffer.toString('base64');
const dataUrl = `data:image/png;base64,${base64}`;
Node.js์์ Base64url ์ธ์ฝ๋ฉ
Node.js 15.7.0 ์ด์์์๋ ๋ค์ดํฐ๋ธ Base64url ์ธ์ฝ๋ฉ์ ์ง์ํ๋ฉฐ, ์ด๋ +๋ฅผ -๋ก, /๋ฅผ _๋ก ๋์ฒดํ๊ณ ํจ๋ฉ์ ์๋ตํฉ๋๋ค:
const encoded = Buffer.from('Hello, world!').toString('base64url');
console.log(encoded);
// Output: SGVsbG8sIHdvcmxkIQ (no padding)
const decoded = Buffer.from(encoded, 'base64url').toString('utf-8');
console.log(decoded);
// Output: Hello, world!
์ฑ๋ฅ ๊ณ ๋ ค ์ฌํญ
๋์ฉ๋ ๋ฐ์ดํฐ์ ๊ฒฝ์ฐ ๋ฐ๋ณต์ ์ธ Base64 ์์ ์ด ๋๋ ค์ง ์ ์์ต๋๋ค. ๋ค์์ ๋ช ๊ฐ์ง ํ์ ๋๋ค:
- ์ ๋์ฝ๋ ๋ฌธ์์ด์๋ ์๋ ๋ณํ๋ณด๋ค
TextEncoder/TextDecoder๋ฅผ ์ฌ์ฉํ์ธ์ - Node.js์์๋
Buffer.from()์ด ๊ณ ๋๋ก ์ต์ ํ๋์ด ์์ผ๋ฏ๋ก ์๋ ๊ตฌํ๋ณด๋ค ์ ํธํ์ธ์ - ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด ๋์ฉ๋ ํ์ผ์ Base64๋ก ๋ณํํ์ง ๋ง์ธ์(์คํธ๋ฆฌ๋ฐ ๊ณ ๋ ค)
- ๋์ฉ๋ ๋ฐ์ดํฐ์
์ ๊ฒฝ์ฐ ๋ธ๋ผ์ฐ์ ์์
Blob๊ณผFileReader๋ฅผ ์ฌ์ฉํ์ฌ ๋ฉ์ธ ์ค๋ ๋ ์ฐจ๋จ์ ๋ฐฉ์งํ์ธ์
์จ๋ผ์ธ์ผ๋ก Base64 ์ธ์ฝ๋ฉ ์ฒดํํ๊ธฐ
์ฝ๋ฉ ์์ด ๋ธ๋ผ์ฐ์ ์์ ๋ฐ๋ก ์ธ์ฝ๋ฉ๊ณผ ๋์ฝ๋ฉ์ ์คํํด ๋ณด์ธ์. ๋ฌด๋ฃ ์จ๋ผ์ธ Base64 ์ธ์ฝ๋ ๋ฐ ๋์ฝ๋๋ฅผ ์ฌ์ฉํ์ธ์. ํ ์คํธ๋ฅผ ๋ถ์ฌ๋ฃ๊ฑฐ๋ ํ์ผ์ ์ ๋ก๋ํ๊ธฐ๋ง ํ๋ฉด ์ฆ์ Base64 ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.