DevToolBox무료
블로그

URL 인코딩 & 디코딩 완전 가이드: 퍼센트 인코딩 해설

10분 읽기by DevToolBox

URL 인코딩(퍼센트 인코딩이라고도 함)은 웹 개발에서 가장 필수적인 메커니즘 중 하나입니다. 폼을 제출하거나, 쿼리 매개변수가 있는 링크를 클릭하거나, REST API를 호출할 때마다 URL 인코딩/디코딩 작업이 수행됩니다. 이 종합 가이드는 RFC 3986 사양부터 JavaScript, Python, Bash, PHP, Java의 실용적인 코드 예제까지 모든 것을 다룹니다.

무료 온라인 URL 인코딩/디코딩 도구를 사용해 보세요.

URL 인코딩(퍼센트 인코딩)이란?

URL 인코딩은 RFC 3986에 정의되어 있으며, 안전하지 않은 문자를 퍼센트 기호(%)와 2자리 16진수로 대체합니다. 예를 들어, 공백은 %20이 됩니다.

URL에는 제한된 ASCII 문자 세트만 포함될 수 있습니다. 인코딩이 필요 없는 URL 안전 문자는: 영문자, 숫자, 4개의 특수 문자 -, _, ., ~입니다. 다른 모든 문자는 인코딩이 필요합니다.

&, =, ?, # 같은 문자는 URL에서 구조적 의미를 가집니다. 적절한 URL 인코딩 없이는 URL이 손상되거나 잘못 해석됩니다.

URL 인코딩 작동 원리

URL 인코딩 프로세스는 간단한 알고리즘을 따릅니다:

  1. 문자를 UTF-8 바이트로 변환.
  2. 각 바이트에 대해 % 뒤에 16진수 값을 기록.
  3. 비예약 문자는 그대로 유지.
  4. 예약 문자는 모호한 경우에만 인코딩.

예제: Hello World!Hello%20World%21이 됩니다.

UTF-8 멀티바이트 예제: 비 ASCII 문자는 여러 퍼센트 인코딩된 바이트를 생성합니다.

URL 인코딩 참조 테이블

자주 인코딩되는 문자의 참조 테이블:

CharacterEncodedDescription
(space)%20Space
!%21Exclamation mark
#%23Hash / Fragment
$%24Dollar sign
%%25Percent sign
&%26Ampersand
'%27Apostrophe
(%28Left parenthesis
)%29Right parenthesis
*%2AAsterisk
+%2BPlus sign
,%2CComma
/%2FForward slash
:%3AColon
;%3BSemicolon
=%3DEquals sign
?%3FQuestion mark
@%40At sign
[%5BLeft bracket
]%5DRight bracket
{%7BLeft brace
}%7DRight brace
|%7CPipe
<%3CLess than
>%3EGreater than
"%22Double quote

공백 인코딩: %20 vs +

URL에서 공백을 인코딩하는 두 가지 방법이 있습니다:

%20: URI의 RFC 3986 표준 인코딩.

+: application/x-www-form-urlencoded(HTML 폼)에서 사용.

어떤 것을 사용할까? 프로그래밍으로 URL을 구성할 때는 %20을 사용하세요. +는 폼 데이터에서 자동으로 사용됩니다.

// Space encoding comparison

// RFC 3986 (URI standard) — space = %20
"hello world"  →  "hello%20world"
// Used in: URL paths, API endpoints, general URIs

// application/x-www-form-urlencoded — space = +
"hello world"  →  "hello+world"
// Used in: HTML form submissions, URLSearchParams

// JavaScript comparison:
encodeURIComponent("hello world")  // "hello%20world"  (%20)
new URLSearchParams({q: "hello world"}).toString()  // "q=hello+world"  (+)

// Python comparison:
urllib.parse.quote("hello world")      # "hello%20world"  (%20)
urllib.parse.urlencode({"q": "hello world"})  # "q=hello+world"  (+)

// PHP comparison:
rawurlencode("hello world")  // "hello%20world"  (%20)
urlencode("hello world")     // "hello+world"    (+)

URL 인코딩/디코딩 코드 예제

JavaScript URL 인코딩/디코딩

JavaScript는 encodeURIComponentencodeURI를 제공합니다. 각각의 사용 시점을 이해하는 것이 중요합니다:

// ===== encodeURIComponent vs encodeURI =====

// encodeURIComponent — encodes EVERYTHING except: A-Z a-z 0-9 - _ . ~
// Use for: individual query parameter values, path segments
encodeURIComponent("hello world & goodbye");
// "hello%20world%20%26%20goodbye"

encodeURIComponent("price=100&category=books");
// "price%3D100%26category%3Dbooks"

// encodeURI — preserves URL structure characters: : / ? # & = @ + $
// Use for: encoding a complete URL
encodeURI("https://example.com/search?q=hello world&lang=en");
// "https://example.com/search?q=hello%20world&lang=en"

// WARNING: Do NOT use encodeURIComponent on full URLs!
encodeURIComponent("https://example.com/path");
// "https%3A%2F%2Fexample.com%2Fpath"  ← BROKEN URL!

// ===== Decoding =====
decodeURIComponent("hello%20world%20%26%20goodbye");
// "hello world & goodbye"

decodeURI("https://example.com/search?q=hello%20world");
// "https://example.com/search?q=hello world"

// ===== URLSearchParams (handles form encoding automatically) =====
const params = new URLSearchParams({
  query: "cats & dogs",
  page: "1",
  filter: "price > 50"
});
params.toString();
// "query=cats+%26+dogs&page=1&filter=price+%3E+50"
// Note: spaces become + (form encoding), & in values becomes %26

// Parse query string
const parsed = new URLSearchParams("?q=hello+world&lang=en");
parsed.get("q");  // "hello world" (+ decoded to space)
parsed.get("lang");  // "en"

// ===== Building URLs with the URL API =====
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "hello world & more");
url.searchParams.set("limit", "10");
url.toString();
// "https://api.example.com/search?q=hello+world+%26+more&limit=10"

Python URL 인코딩/디코딩

Python의 urllib.parse 모듈은 포괄적인 URL 인코딩 함수를 제공합니다:

import urllib.parse

# ===== quote / unquote (RFC 3986 percent-encoding) =====

# Encode a string (spaces become %20)
urllib.parse.quote("hello world & goodbye")
# "hello%20world%20%26%20goodbye"

# By default, / is NOT encoded (safe="/")
urllib.parse.quote("/path/to/file name.txt")
# "/path/to/file%20name.txt"

# Encode everything including /
urllib.parse.quote("/path/to/file", safe="")
# "%2Fpath%2Fto%2Ffile"

# Decode
urllib.parse.unquote("hello%20world%20%26%20goodbye")
# "hello world & goodbye"

# ===== urlencode (for query strings, uses + for spaces) =====
params = {"q": "cats & dogs", "page": 1, "filter": "price > 50"}
urllib.parse.urlencode(params)
# "q=cats+%26+dogs&page=1&filter=price+%3E+50"

# ===== quote_plus (form encoding, spaces become +) =====
urllib.parse.quote_plus("hello world")
# "hello+world"

urllib.parse.unquote_plus("hello+world")
# "hello world"

# ===== With the requests library =====
import requests

# requests handles URL encoding automatically
response = requests.get(
    "https://api.example.com/search",
    params={"q": "hello world", "lang": "en"}
)
# Actual URL: https://api.example.com/search?q=hello+world&lang=en

# For path segments, encode manually
username = "john@example.com"
url = f"https://api.example.com/users/{urllib.parse.quote(username, safe='')}"
# "https://api.example.com/users/john%40example.com"

Bash / curl URL 인코딩

curl의 --data-urlencode 플래그가 가장 간단한 방법입니다:

# ===== curl --data-urlencode =====

# GET request with URL-encoded query parameter
curl -G "https://api.example.com/search" \
  --data-urlencode "q=hello world & more" \
  --data-urlencode "lang=en"
# Request URL: /search?q=hello%20world%20%26%20more&lang=en

# POST with form-encoded body
curl -X POST "https://api.example.com/submit" \
  --data-urlencode "name=John Doe" \
  --data-urlencode "message=Hello! How are you?"

# ===== Pure Bash URL encoding (using printf) =====
urlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""
  local pos c o
  for (( pos=0 ; pos<strlen ; pos++ )); do
    c=${string:$pos:1}
    case "$c" in
      [-_.~a-zA-Z0-9]) o="${c}" ;;
      *) printf -v o '%%%02X' "'$c" ;;
    esac
    encoded+="${o}"
  done
  echo "${encoded}"
}

urlencode "hello world & goodbye"
# "hello%20world%20%26%20goodbye"

# ===== Using Python one-liner in Bash =====
python3 -c "import urllib.parse; print(urllib.parse.quote('hello world'))"
# "hello%20world"

# ===== Decode URL-encoded strings =====
python3 -c "import urllib.parse; print(urllib.parse.unquote('hello%20world'))"
# "hello world"

PHP URL 인코딩/디코딩

PHP는 urlencode()rawurlencode()를 제공합니다:

<?php
// ===== urlencode / urldecode =====
// Uses + for spaces (application/x-www-form-urlencoded)

echo urlencode("hello world & goodbye");
// "hello+world+%26+goodbye"

echo urldecode("hello+world+%26+goodbye");
// "hello world & goodbye"

// ===== rawurlencode / rawurldecode =====
// Uses %20 for spaces (RFC 3986)

echo rawurlencode("hello world & goodbye");
// "hello%20world%20%26%20goodbye"

echo rawurldecode("hello%20world%20%26%20goodbye");
// "hello world & goodbye"

// ===== When to use which? =====
// urlencode()    → for query string values (form-style)
// rawurlencode() → for URL path segments (RFC 3986)

// Building a URL with encoded path and query
$path = rawurlencode("my file.pdf");
$query = urlencode("search term & more");
$url = "https://example.com/files/{$path}?q={$query}";
// "https://example.com/files/my%20file.pdf?q=search+term+%26+more"

// ===== http_build_query (encode arrays as query strings) =====
$params = [
    "q" => "cats & dogs",
    "page" => 1,
    "tags" => ["php", "url encoding"]
];
echo http_build_query($params);
// "q=cats+%26+dogs&page=1&tags%5B0%5D=php&tags%5B1%5D=url+encoding"
?>

Java URL 인코딩/디코딩

Java의 URLEncoderURLDecoder 클래스가 URL 인코딩을 처리합니다:

import java.net.URLEncoder;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

// ===== URLEncoder.encode (uses + for spaces) =====

// Always specify UTF-8 charset!
String encoded = URLEncoder.encode(
    "hello world & goodbye", StandardCharsets.UTF_8
);
// "hello+world+%26+goodbye"

// Decode
String decoded = URLDecoder.decode(
    "hello+world+%26+goodbye", StandardCharsets.UTF_8
);
// "hello world & goodbye"

// ===== Convert + to %20 for RFC 3986 compliance =====
String rfc3986 = URLEncoder.encode("hello world", StandardCharsets.UTF_8)
    .replace("+", "%20");
// "hello%20world"

// ===== Java 11+ URI encoding =====
import java.net.URI;

URI uri = URI.create("https://example.com/search");
// For building URLs with encoded parameters:
String query = "q=" + URLEncoder.encode("hello world", StandardCharsets.UTF_8);
URI fullUri = URI.create("https://example.com/search?" + query);
// https://example.com/search?q=hello+world

// ===== Encoding path segments =====
String pathSegment = URLEncoder.encode("my file.pdf", StandardCharsets.UTF_8)
    .replace("+", "%20");
String url = "https://example.com/files/" + pathSegment;
// "https://example.com/files/my%20file.pdf"

일반적인 URL 인코딩 실수

피해야 할 가장 흔한 함정들:

이중 인코딩: 이미 인코딩된 문자열을 다시 인코딩. %20%2520이 됩니다.

// Double encoding example — a common bug!

const value = "hello world";

// Correct: encode once
const correct = encodeURIComponent(value);
// "hello%20world" ✓

// Bug: encode twice
const doubleEncoded = encodeURIComponent(encodeURIComponent(value));
// "hello%2520world" ✗  (%25 is the encoded form of %)

// How to detect double encoding:
// If you see %25 in your URLs, you likely have a double encoding issue
// %2520 = double-encoded space (%25 = %, 20 = space)
// %253A = double-encoded colon (%25 = %, 3A = :)

전체 URL 인코딩: 전체 URL에 encodeURIComponent()를 사용하면 URL 구조가 깨집니다.

// Encoding the entire URL — WRONG!
const url = "https://example.com/path?q=hello world";

// WRONG: breaks URL structure
encodeURIComponent(url);
// "https%3A%2F%2Fexample.com%2Fpath%3Fq%3Dhello%20world"

// CORRECT option 1: use encodeURI for full URLs
encodeURI(url);
// "https://example.com/path?q=hello%20world"

// CORRECT option 2: encode only the value
const base = "https://example.com/path";
const query = encodeURIComponent("hello world");
const fullUrl = base + "?q=" + query;
// "https://example.com/path?q=hello%20world"

UTF-8 누락: URL 인코딩에는 항상 UTF-8을 사용하세요.

경로 세그먼트 인코딩 누락: 공백이 포함된 경로도 인코딩이 필요합니다.

+ 기호 잘못 처리: +는 폼에서 공백을 의미하지만 일반 URL에서는 리터럴입니다.

API에서의 URL 인코딩

API에서 올바른 URL 인코딩은 중요합니다:

쿼리 매개변수: 각 매개변수 이름과 값을 개별적으로 인코딩해야 합니다.

경로 매개변수: URL 경로에 포함된 값도 인코딩이 필요합니다.

폼 데이터: application/x-www-form-urlencoded는 공백에 +를 사용합니다.

JSON 페이로드: 요청 본문의 JSON 콘텐츠는 URL 인코딩이 필요 없습니다.

// API URL encoding examples

// Query parameters — encode each value individually
const searchTerm = 'price > 100 & category = "electronics"';
const apiUrl = `https://api.example.com/search?q=${encodeURIComponent(searchTerm)}&limit=10`;
// "https://api.example.com/search?q=price%20%3E%20100%20%26%20...&limit=10"

// Path parameters — encode values embedded in paths
const username = "john@example.com";
const profileUrl = `https://api.example.com/users/${encodeURIComponent(username)}/profile`;
// "https://api.example.com/users/john%40example.com/profile"

// Form data (POST) — uses + for spaces
const formBody = new URLSearchParams({
  username: "john doe",
  password: "p@ss w0rd!"
}).toString();
// "username=john+doe&password=p%40ss+w0rd%21"

// JSON as query parameter — encode the entire JSON string
const filters = JSON.stringify({ price: { min: 10, max: 100 } });
const url = `/api/products?filters=${encodeURIComponent(filters)}`;
// "/api/products?filters=%7B%22price%22%3A%7B%22min%22%3A10%2C%22max%22%3A100%7D%7D"

자주 묻는 질문

URL 인코딩이란 무엇이며 왜 필요한가요?

URL 인코딩은 안전하지 않은 문자를 퍼센트-16진수 시퀀스로 대체하여 URL에서 안전하게 전송하기 위한 프로세스입니다. &, =, ?, # 같은 특수 문자는 구조적 의미를 가지며 데이터로 사용할 때 인코딩이 필요합니다.

encodeURI와 encodeURIComponent의 차이점은?

encodeURI()는 URL 구조 문자(:, /, ?, #)를 보존합니다. encodeURIComponent()는 비예약 문자를 제외한 모든 것을 인코딩합니다. 개별 매개변수 값에는 encodeURIComponent를 사용하세요.

공백에 %20과 + 중 어떤 것을 사용해야 하나요?

URL(RFC 3986)에는 %20을 사용하세요. application/x-www-form-urlencoded에만 +를 사용하세요. 확실하지 않으면 %20이 더 안전한 선택입니다.

URL 인코딩은 모든 개발자가 매일 접하는 기본적인 웹 개발 기술입니다. 무료 온라인 도구로 즉시 인코딩과 디코딩을 수행하세요.

무료 온라인 도구로 URL을 즉시 인코딩하고 디코딩하세요.

𝕏 Twitterin LinkedIn
도움이 되었나요?

최신 소식 받기

주간 개발 팁과 새 도구 알림을 받으세요.

스팸 없음. 언제든 구독 해지 가능.

Try These Related Tools

%20URL Encoder/Decoder🔗URL Parser%←URL Decoder%%Percent Encoding Tool

Related Articles

URL 인코딩 특수문자: 완전한 참조 테이블 & 예제

URL 퍼센트 인코딩 완전 참조. 모든 특수문자 조회표, encodeURIComponent vs encodeURI 사용법.

Base64 인코딩 & 디코딩 완전 가이드: 코드 예제 포함

무료 온라인 Base64 인코더/디코더. JavaScript, Python, Bash, PowerShell 코드 예제와 함께 Base64 원리를 배우세요.

URL 인코더 디코더 온라인 가이드: 퍼센트 인코딩, RFC 3986, 모범 사례

URL 인코딩(퍼센트 인코딩) 완전 가이드. RFC 3986 예약 및 비예약 문자, encodeURIComponent vs encodeURI, Python urllib.parse, Java URLEncoder, 일반 인코딩 문자, 폼 인코딩, API 쿼리 매개변수, 이중 인코딩 디버깅.