ToolDeck

URL 파서

URL을 프로토콜, 호스트, 경로, 쿼리 파라미터, 해시로 분석

예시 시도
이것도 써보세요:URL Encode OnlineURL Decode Online

URL 파싱이란?

URL 파싱은 Uniform Resource Locator를 개별 구성 요소인 프로토콜(스킴), 호스트명, 포트, 경로명, 쿼리 파라미터, 프래그먼트 식별자로 분해하는 과정입니다. 모든 URL은 RFC 3986과 WHATWG URL 표준에서 정의한 구조를 따릅니다. URL 파서는 원시 문자열을 읽고 구분 문자(://, :, /, ?, #, &, =)를 기준으로 각 세그먼트를 식별하여 별도의 접근 가능한 필드로 반환합니다.

브라우저는 주소를 입력하거나 링크를 클릭할 때마다 URL 파싱을 수행합니다. JavaScript의 URL 생성자, Python의 urllib.parse 모듈, Go의 net/url 패키지는 모두 동일한 구조 규칙을 따르는 파서를 구현합니다. URL 파싱은 URL 인코딩의 역과정입니다. 안전한 전송을 위해 문자를 변환하는 대신, 이미 구성된 URL을 구성하는 부분들로 분해합니다.

https://api.example.com:8080/v1/users?page=2&limit=10#section과 같은 일반적인 URL에는 여섯 가지 구성 요소가 있습니다. 구분 문자인 ://, :, /, ?, &, =, # 가 파싱을 결정론적으로 만듭니다. 각 문자는 경계를 나타내어 파서가 모호함 없이 필드를 추출할 수 있도록 합니다.

온라인 URL 파서를 사용하는 이유

눈으로 URL을 수동으로 분리하는 것은 오류가 발생하기 쉽습니다. 특히 인코딩된 문자, 여러 쿼리 파라미터, 비표준 포트가 포함된 경우 더욱 그렇습니다. 이 도구는 브라우저가 사용하는 것과 동일한 WHATWG 호환 알고리즘을 사용하여 URL을 파싱하고 모든 구성 요소를 명확하게 복사 가능한 테이블로 표시합니다.

브라우저에서 즉시 파싱
URL을 붙여넣으면 모든 구성 요소가 즉시 분해되어 표시됩니다. 페이지 리로드, 서버 호출, 대기 시간 없음.
🔒
URL을 비공개로 유지
파싱은 네이티브 URL API를 사용하여 브라우저에서만 실행됩니다. 입력한 URL은 절대 기기를 벗어나지 않습니다.
🔍
모든 세부 정보 확인
프로토콜, 호스트명, 포트, 경로명, 쿼리 문자열, 해시, 그리고 디코딩된 값과 함께 각 쿼리 파라미터를 개별적으로 확인하세요.
📋
개별 구성 요소 복사
각 필드 옆의 복사 버튼을 클릭하면 정확한 값을 가져올 수 있습니다. 수동으로 부분 문자열을 선택하고 다듬을 필요가 없습니다.

URL 파서 사용 사례

프론트엔드 라우팅 디버깅
경로 세그먼트와 해시 프래그먼트가 라우터 설정과 일치하는지 확인하세요. 404 오류가 발생하기 전에 잘못 놓인 슬래시나 예상치 못한 쿼리 파라미터를 발견하세요.
백엔드 API 엔드포인트 검증
라우트 핸들러나 미들웨어를 작성하기 전에 수신 요청 URL에 올바른 호스트명, 포트, 경로 구조가 포함되어 있는지 확인하세요.
DevOps 리다이렉트 규칙 테스트
Nginx, Apache, CDN 리다이렉트 규칙을 작성할 때 원본 URL과 대상 URL을 파싱하여 각 구성 요소가 올바르게 매핑되는지 확인하세요.
QA 링크 검증
테스트 보고서나 버그 티켓의 URL을 파싱하여 잘못된 페이지가 로드되는 원인이 되는 쿼리 파라미터나 프래그먼트를 격리하세요.
데이터 파이프라인 URL 추출
로그 파일이나 분석 데이터의 URL에서 호스트명이나 경로 세그먼트를 추출하여 도메인 수준 보고서를 작성하거나 엔드포인트별로 트래픽을 필터링하세요.
URL 구조 학습
웹 프로토콜을 처음 접하는 학생이나 개발자는 실제 URL을 붙여넣어 어떤 구분 문자가 어떤 경계를 나타내는지 바로 확인할 수 있습니다.

URL 구성 요소 참조

아래 표는 URL을 파싱할 때 JavaScript URL 생성자가 반환하는 모든 속성을 보여줍니다. Python의 urlparse 결과, Go의 url.URL 구조체, PHP의 parse_url 출력에도 동일한 구성 요소가 존재하지만 언어마다 속성 이름이 다릅니다.

속성예시설명
protocolhttps:Scheme including the trailing colon
hostnameapi.example.comDomain name or IP address
port8080Port number (empty string if default)
pathname/v1/usersPath starting with /
search?page=2&limit=10Query string including the leading ?
hash#sectionFragment identifier including the leading #
originhttps://api.example.com:8080protocol + hostname + port
hostapi.example.com:8080hostname + port
usernameadminCredentials before @ (rarely used in practice)
passwordsecretCredentials before @ (avoid in production URLs)
href(full URL)The complete, serialized URL string

WHATWG URL 표준 vs RFC 3986

URL 파싱 방법을 정의하는 두 가지 사양이 있습니다. 기본 구조에는 동의하지만 엣지 케이스에서 차이가 있습니다. 이 차이가 브라우저와 서버가 URL을 다르게 처리할 때의 원인이 되는 경우가 많습니다.

WHATWG URL Standard
모든 현대 브라우저와 JavaScript URL 생성자가 사용합니다. 잘못된 입력을 수용하고 정규화합니다: 누락된 스킴, 경로 구분자로서의 백슬래시, Punycode를 통한 비 ASCII 호스트명. url.spec.whatwg.org에서 생활 표준으로 정의됩니다.
RFC 3986
공식 IETF 사양(2005년). WHATWG보다 엄격합니다: 브라우저가 허용하는 일부 입력을 거부합니다. Go의 net/url, Python의 urllib.parse를 포함한 많은 서버 측 라이브러리에서 사용됩니다. RFC 3986에서 정의됩니다.

실제로 대부분의 차이는 국제 도메인 이름(IDN), 누락된 스킴, 비정상적인 문자가 포함된 URL을 파싱할 때 나타납니다. WHATWG 파서는 IDN 호스트명을 자동으로 Punycode로 변환하는 반면, 엄격한 RFC 3986 파서는 이를 거부할 수 있습니다. URL을 이 도구에 붙여넣었을 때 서버 측 코드와 다른 결과가 나온다면, WHATWG vs RFC 차이가 가장 가능성 있는 원인입니다.

코드 예시

주요 언어에는 모두 내장 URL 파서가 있습니다. 아래 예시는 동일한 URL을 파싱하여 구성 요소를 추출합니다. 언어마다 이름 차이가 있습니다: Python은 protocol 대신 scheme을 사용하고, Go는 search 대신 RawQuery를 노출합니다.

JavaScript (browser / Node.js)
const url = new URL('https://api.example.com:8080/v1/users?page=2&limit=10#section')

url.protocol  // → "https:"
url.hostname  // → "api.example.com"
url.port      // → "8080"
url.pathname  // → "/v1/users"
url.search    // → "?page=2&limit=10"
url.hash      // → "#section"

// Iterate over query parameters
for (const [key, value] of url.searchParams) {
  console.log(`${key} = ${value}`)
}
// → "page = 2"
// → "limit = 10"

// Modify and re-serialize
url.searchParams.set('page', '3')
url.toString()
// → "https://api.example.com:8080/v1/users?page=3&limit=10#section"
Python
from urllib.parse import urlparse, parse_qs

result = urlparse('https://api.example.com:8080/v1/users?page=2&limit=10#section')

result.scheme    # → 'https'
result.hostname  # → 'api.example.com'
result.port      # → 8080
result.path      # → '/v1/users'
result.query     # → 'page=2&limit=10'
result.fragment  # → 'section'

# Parse query string into a dict
params = parse_qs(result.query)
params['page']   # → ['2']
params['limit']  # → ['10']

# Reconstruct with modifications
from urllib.parse import urlencode, urlunparse
new_query = urlencode({'page': '3', 'limit': '10'})
urlunparse(result._replace(query=new_query))
# → 'https://api.example.com:8080/v1/users?page=3&limit=10#section'
Go
package main

import (
	"fmt"
	"net/url"
)

func main() {
	u, err := url.Parse("https://api.example.com:8080/v1/users?page=2&limit=10#section")
	if err != nil {
		panic(err)
	}

	fmt.Println(u.Scheme)   // → "https"
	fmt.Println(u.Hostname()) // → "api.example.com"
	fmt.Println(u.Port())     // → "8080"
	fmt.Println(u.Path)       // → "/v1/users"
	fmt.Println(u.RawQuery)   // → "page=2&limit=10"
	fmt.Println(u.Fragment)   // → "section"

	// Query params as map
	q := u.Query()
	fmt.Println(q.Get("page"))  // → "2"
	fmt.Println(q.Get("limit")) // → "10"
}
PHP
<?php
$url = 'https://api.example.com:8080/v1/users?page=2&limit=10#section';
$parts = parse_url($url);

$parts['scheme'];   // → "https"
$parts['host'];     // → "api.example.com"
$parts['port'];     // → 8080
$parts['path'];     // → "/v1/users"
$parts['query'];    // → "page=2&limit=10"
$parts['fragment']; // → "section"

// Parse query string into an array
parse_str($parts['query'], $params);
$params['page'];    // → "2"
$params['limit'];   // → "10"

자주 묻는 질문

URL과 URI의 차이점은 무엇인가요?
URL(Uniform Resource Locator)은 식별자와 접근 방법(https://와 같은 스킴)을 모두 포함하는 URI(Uniform Resource Identifier)의 특정 유형입니다. 모든 URL은 URI이지만, 모든 URI가 URL인 것은 아닙니다. urn:isbn:0451450523과 같은 URN은 검색 방법을 명시하지 않고 이름으로 리소스를 식별하는 URI입니다. 웹 개발에서 마주치는 거의 모든 URI가 URL이기 때문에 두 용어는 종종 혼용됩니다.
URL 생성자는 상대 URL을 어떻게 처리하나요?
JavaScript URL 생성자는 상대 경로를 파싱할 때 기본 URL이 필요합니다. new URL('/path?q=1')을 호출하면 TypeError가 발생합니다. 기본 URL을 제공해야 합니다: new URL('/path?q=1', 'https://example.com'). Python의 urljoin과 Go의 url.ResolveReference도 동일한 목적으로 사용됩니다. 이 도구는 스킴이 있는 완전한 절대 URL을 기대합니다.
URL에 포트 번호가 없으면 어떻게 되나요?
포트가 생략되면 파서는 port 속성에 빈 문자열을 반환합니다. 브라우저는 스킴에 따라 기본 포트를 가정합니다: https는 443, http는 80, ftp는 21. origin이나 host 속성을 통해 유효 포트에 접근할 수 있지만, 명시적 포트가 지정되지 않았으므로 port 필드 자체는 비어 있습니다.
URL에 유니코드 문자를 포함할 수 있나요?
네, 하지만 전송을 위해 인코딩해야 합니다. WHATWG URL 표준은 이를 자동으로 처리합니다: 국제 도메인 이름은 Punycode(xn-- 접두사)로 변환되고, ASCII 범위 밖의 경로/쿼리 문자는 퍼센트 인코딩됩니다. 유니코드가 포함된 URL을 이 도구에 붙여넣으면 파싱 결과에 정규화된 ASCII 안전 버전이 표시됩니다.
URL의 최대 길이는 얼마인가요?
최대 URL 길이를 정의하는 표준은 없습니다. RFC 3986은 이 주제에 대해 침묵합니다. 실제로 브라우저마다 제한이 있습니다: Chrome은 주소 표시줄에서 약 2MB를 지원하고, Internet Explorer(레거시)는 2,083자 제한이 있었습니다. 대부분의 웹 서버는 요청 줄에 대해 기본적으로 8KB(Nginx) 또는 8KB(Apache)를 사용합니다. 대용량 데이터를 전달해야 한다면 쿼리 문자열 대신 POST 요청 본문을 사용하세요.
전체 URL 없이 쿼리 문자열만 파싱하려면 어떻게 하나요?
JavaScript에서는 new URLSearchParams('page=2&limit=10')을 사용하여 단독 쿼리 문자열을 파싱하세요. Python에서는 urllib.parse.parse_qs('page=2&limit=10')를 사용하세요. 두 방법 모두 파라미터를 키-값 쌍으로 반환합니다. 폼 제출이나 쿼리 부분만 캡처한 로그 항목처럼 쿼리 문자열을 단독으로 가지고 있을 때 유용합니다.
URL 파싱과 URL 디코딩은 같은 건가요?
아닙니다. URL 파싱은 URL을 구조적 구성 요소(스킴, 호스트, 경로, 쿼리, 프래그먼트)로 분리합니다. URL 디코딩은 퍼센트 인코딩된 문자를 원래 형태로 변환합니다(%20은 공백이 되고, %26은 &가 됩니다). 두 작업은 상호 보완적입니다: 일반적으로 URL을 먼저 파싱한 다음 개별 구성 요소 값을 디코딩합니다. 파싱 전에 디코딩하면 디코딩된 &와 = 같은 구분 문자가 잘못 해석될 수 있으므로 URL 구조가 손상될 수 있습니다.