웹 개발 하다보면, 이렇게 %
가 들어간 URL을 보게됩니다.
https://velog.io/@skyepodium/URL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
대충 경험으로 URL 인코딩 되었구나 하고 넘어갔는데, 왜하는걸까
URL 인코딩은 URL에 문자를 표현하는 문자 인코딩 방법입니다.
URL에는 아스키만 사용 가능하기 때문에,
아스키가 아닌 문자
는 유니코드 인코딩 후 % + 16진수
로 변환하고 (한글, 일본어 등
)
아스키 문자이면서 예약된 문자
는 원래의 목적으로 사용될 수 있도록 16진수 변환합니다. ("!*'();:@&=+$,/?#[]"
)
예약된 문자에 포함된 슬래시('/') 는 url의 다른 부분을 구분하는 역할을 합니다.
(참고: https://www.rfc-editor.org/rfc/rfc3986 - 주의: 전부 다 영어, 굳이 안봐도 좋은듯)
url 인코딩 안하는 경우 axios에서는 제대로 요청하지 못하고, python reuqets 모듈을 요청이 가능한데 다 외우고 다닐것 아니면 인코딩 해줍시다.
const axios = require('axios')
const originalUrl = 'https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현'
const encodedUrl = encodeURI(originalUrl)
const httpGetRequest = async (requestedUrl) => {
try {
await axios.get(requestedUrl)
console.log(`requestedUrl: ${requestedUrl} - 요청성공`)
} catch (err) {
console.log(`requestedUrl: ${requestedUrl} - 에러`)
}
}
httpGetRequest(originalUrl)
// requestedUrl: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현 - 에러
httpGetRequest(encodedUrl)
// requestedUrl: https://velog.io/@skyepodium/URL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84 - 요청성공
여러가지가 있는데요, 사이버 쉐프가 제일 편한것 같아요 공유하기도 편하고 자동으로 알고리즘 추천도 해줍니다.
사이버 쉐프 링크: https://gchq.github.io/CyberChef/#recipe=URL_Decode()&input=aHR0cHM6Ly92ZWxvZy5pby9Ac2t5ZXBvZGl1bS9VUkwtJUVDJTlEJUI4JUVDJUJEJTk0JUVCJTk0JUE5LSVFQyU5NSU4QyVFQyU5NSU4NCVFQiVCMyVCNCVFQSVCOCVCMC1mZWF0Li0lRUQlOEMlOEMlRUMlOUQlQjQlRUMlOEQlQUMtJUVBJUI1JUFDJUVEJTk4JTg0Cg
예약된 문자열 인코딩 하는 경우/인코딩 하지 않는 경우 분기처리
const originalUrl = 'https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현'
// 1) 예약 문자 인코딩 안함
var encodedUrl = encodeURI(originalUrl)
console.log('encodedUrl: ', encodedUrl)
// encodedUrl: https://velog.io/@skyepodium/URL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
var decodedUrl = decodeURI(encodedUrl)
console.log('decodedUrl: ', decodedUrl)
// decodedUrl: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
// 2) 예약 문자 인코딩 함
var encodedUrl = encodeURIComponent(originalUrl)
console.log('encodedUrl: ', encodedUrl)
// encodedUrl: https%3A%2F%2Fvelog.io%2F%40skyepodium%2FURL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
var decodedUrl = decodeURIComponent(encodedUrl)
console.log('decodedUrl: ', decodedUrl)
// decodedUrl: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
from urllib.parse import unquote, quote
originalUrl = 'https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현'
print("originalUrl: ", originalUrl)
# https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
print()
# 1) 예약 문자 인코딩 안함
encodedUrl = quote(originalUrl, safe='/%:@&=+$,!?*\'()')
print("encodedUrl: ", encodedUrl)
# https://velog.io/@skyepodium/URL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
# URL 디코딩
decodedUrl = unquote(encodedUrl)
print("decodedUrl: ", decodedUrl)
# https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
print()
# 2) 예약 문자 인코딩 함
encodedUrl = quote(originalUrl, safe='')
print("encodedUrl: ", encodedUrl)
# https%3A%2F%2Fvelog.io%2F%40skyepodium%2FURL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
# URL 디코딩
decodedUrl = unquote(encodedUrl)
print("decodedUrl: ", decodedUrl)
# https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
예약된 문자열 인코딩 하는 경우, 인코딩 하지 않는 경우를 분기처리 했습니다.
원래 URL
https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
예약된 문자 인코딩 하는 경우
https%3A%2F%2Fvelog.io%2F%40skyepodium%2FURL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
예약된 문자 인코딩 하지 않는 경우 (진짜 벨로그 주소 같아졌다)
https://velog.io/@skyepodium/URL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
class urlparser:
def __init__(self):
# 예약되지 않은 문자
self.UNRESERVED_TEXT_SET = set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~")
# 예약된 문자
self.RESERVED_TEXT_SET = set("!*'();:@&=+$,/?#[]")
def encode(self, url: str, is_reserved_text_encode: bool) -> str:
encoded = []
for char in url:
# 1) 아스키 문자이고, 예약되지 않은 문자는 그대로 넣습니다.
if char in self.UNRESERVED_TEXT_SET:
encoded.append(char)
# 2) 아스키 문자이고, 예약된 문자는 16진수로 넣습니다.
elif char in self.RESERVED_TEXT_SET:
# 예약된 문자도 모두 인코딩 하는 경우
if is_reserved_text_encode:
encoded.append("%{:02X}".format(ord(char)))
# 예약된 문자를 인코딩 하지 않는 겨웅 그대로 넣습니다.
else:
encoded.append(char)
# 3) 아스키가 문자가 아니면, UTF-8로 인코딩후 2자리씩 끊어서 대문자로 넣습니다.
else:
encoded_str = char.encode('utf-8').hex()
for i in range(0, len(encoded_str), 2):
encoded.append(f"%{encoded_str[i:i + 2].upper()}")
return "".join(encoded)
def decode(self, url: str) -> str:
decoded = []
# 1) %로 시작하는 문자열을 찾습니다.
i = 0
while i < len(url):
if url[i] == '%':
hex_str = url[i + 1:i + 3]
decoded_str = chr(int(hex_str, 16))
# 1) 아스키 문자이고, 예약된 문자인 경우
if decoded_str in self.RESERVED_TEXT_SET:
decoded.append(decoded_str)
i += 3
# 2) 아스키가 아닌 문자인 경우 3바이트 끊어서 디코딩합니다.
else:
hex_str = url[i:i + 9].replace("%", "")
decoded_str = bytes.fromhex(hex_str).decode('utf-8')
decoded.append(decoded_str)
i += 9
# 3) 아스키 문자이고, 예약되지 않은 문자는 그대로 넣습니다.
else:
decoded.append(url[i])
i += 1
return "".join(decoded)
url_parser = urlparser()
original_url = "https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현"
print('원래 url:', original_url)
# 원래 url: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
print()
# 1) 예약된 문자열 인코딩하는 경우
encoded_url = url_parser.encode(original_url, True)
print('1) 예약된 문자열 인코딩하는 경우: ', encoded_url)
# 인코딩 url: https%3A%2F%2Fvelog.io%2F%40skyepodium%2FURL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
decoded_url = url_parser.decode(encoded_url)
print('디코딩 url:', decoded_url)
# 디코딩 url: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현
print()
# 2) 예약된 문자열은 인코딩 하지 않는 경우
encoded_url = url_parser.encode(original_url, False)
print('2) 예약된 문자열은 인코딩 하지 않는 경우: ', encoded_url)
# 인코딩 url: https%3A%2F%2Fvelog.io%2F%40skyepodium%2FURL-%EC%9D%B8%EC%BD%94%EB%94%A9-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-feat.-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EA%B5%AC%ED%98%84
decoded_url = url_parser.decode(encoded_url)
print('디코딩 url:', decoded_url)
# 디코딩 url: https://velog.io/@skyepodium/URL-인코딩-알아보기-feat.-파이썬-구현