get요청으로 보내는 url encoding error 해결하기

Maliethy·2021년 10월 11일
0

react error

목록 보기
3/7

1. issue

다음과 같은 productIDs를 담은 쿼리를 get 요청으로 보낼 때

예)Request URL에 담는 productIDs의 형태: 선택=대 2개+중 5매+소(5매), 샘플 1개
Request URL: http://localhost:3060/Web/StoreProductIDSyncList?productIDs=%EC%84%A0%ED%83%9D=%ED%86%A4%EC%97%85%ED%81%AC%EB%A6%BC%201%EA%B0%9C+%EC%83%98%ED%94%8C%205%EB%A7%A4&productIDs=%EC%84....

다음과 같은 productIDs를 get요청으로 url에 담아 보내니 internal server error 500이 발생했다.

Request URL에 대괄호와 소괄호가 encoding되지 않고 서버로 가지도 못하고 nextjs 서버에서 'type error: Request path contains unescaped characters' 가 발생한 것이다. redux-toolkit에서 기본적으로 encoding을 해주지만 특수문자의 경우 추가로 변환을 해줘야 하는 상황으로 보여 encoding를 해주는 대표적인 method인 escape, encodeURI, encodeURIComponent를 사용해 비교해보았다.

2. solution

//사용된 특수문자: =, +, (, )

console.log("escape():", escape("선택=대 2개+중 5매+소(5매), 샘플 1개"));
console.log("encodeURI():", encodeURI("선택=대 2개+중 5매+소(5매), 샘플 1개"));
console.log(
  "encodeURIComponent():",
  encodeURIComponent("선택=대 2개+중 5매+소(5매), 샘플 1개")
);


// escape(): %uC120%uD0DD%3D%uB300%202%uAC1C+%uC911%205%uB9E4+%20%uC18C%285%uB9E4%29%2C%20%uC0D8%uD50C%201%uAC1C
// encodeURI(): %EC%84%A0%ED%83%9D=%EB%8C%80%202%EA%B0%9C+%EC%A4%91%205%EB%A7%A4+%20%EC%86%8C(5%EB%A7%A4),%20%EC%83%98%ED%94%8C%201%EA%B0%9C
// encodeURIComponent(): %EC%84%A0%ED%83%9D%3D%EB%8C%80%202%EA%B0%9C%2B%EC%A4%91%205%EB%A7%A4%2B%20%EC%86%8C(5%EB%A7%A4)%2C%20%EC%83%98%ED%94%8C%201%EA%B0%9C

encodeURI, encodeURIComponent의 경우 소괄호는 encoding되지 못한 것을 볼 수 있다.
그래서 escape을 사용해 서버로 보내기는 성공하였으나 + 값이 space로 변환되어 값이 다음과 같이 들어가는 모습을 보였다.

productIDs: 선택=대 2개 중 5매 소(5매), 샘플 1개

escape의 경우는 +가 변환되지 않는데 서버에서는 +를 문자가 아닌 연산기호로 인식한 듯 했다.
결국 get요청을 post요청으로 서버측에서 변경해 해당 문제를 해결했다.
이 문제를 겪으며 주요 encoding method를 정리해보기로 한다.

각 method별로 변환되지 않는 특수문자를 정리하면 다음과 같다.

  • escape의 경우: @*_+-./ 는 제외
  • encodeURI의 경우: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # 는 제외
  • encodeURIComponent의 경우: A-Z a-z 0-9 - _ . ! ~ * ' ( ) 는 제외

encodeURI, encodeURIComponent의 중요한 차이점은 encodeURI()에 대한 설명 중 다음의 특성을 들 수 있다.

encodeURI() 혼자서는 XMLHttpRequest 등이 사용할, 적합한 HTTP GET과 POST 요청을 구성할 수 없습니다. GET과 POST에서 특별한 문자로 취급하는 "&", "+", "="를 인코딩 하지 않기 때문입니다. 그러나 encodeURIComponent()는 저 세 문자도 인코딩 대상에 포함합니다.

둘을 비교한 예시를 mdn에서 가져와 다시 정리해보면 다음과 같다.

const set1 = ";,/?:@&=+$"; // 예약 문자, Reserved Characters(encodeURIComponent만 변환됨)
const set2 = "-_.!~*'()"; // 비예약 표식, Unescaped Characters(encodeURI, encodeURIComponent 둘다 변환 안됨)
const set3 = "#"; // Number Sign(encodeURIComponent만 변환됨)

console.log(encodeURI(set1)); // ;,/?:@&=+$
console.log(encodeURI(set2)); // -_.!~*'()
console.log(encodeURI(set3)); // #

console.log(encodeURIComponent(set1)); // %3B%2C%2F%3F%3A%40%26%3D%2B%24
console.log(encodeURIComponent(set2)); // -_.!~*'()
console.log(encodeURIComponent(set3)); // %23

한편 escape()는 ECMA-262 standard에서는 부속품으로 분류되므로 사용하지 않는 것이 좋다고 되어 있다.

Warning: Although escape() is not strictly deprecated (as in "removed from the Web standards"), it is defined in Annex B of the ECMA-262 standard, whose introduction states:
… All of the language features and behaviors specified in this annex have one or more undesirable characteristics and in the absence of legacy usage would be removed from this specification. … … Programmers should not use or assume the existence of these features and behaviors when writing new ECMAScript code. …
(이 부속문서에 명시된 모든 언어 특징과 행동은 하나 이상의 바람직하지 않은 특성을 가지고 있으며, 레거시 사용이 없을 경우 이 명세서에서 삭제될 수 있다. … … 프로그래머는 새로운 ECMAScript 코드를 작성할 때 이러한 특징과 행동의 존재를 사용하거나 가정해서는 안 됩니다. …)

따라서 encodeURIComponent을 포함한 다음과 같은 함수를 만들어 사용하는 것이 가장 좋은 해법인 듯 하다.

To be more stringent in adhering to RFC 3986 (which reserves !, ', (, ), and ), even though these characters have no formalized URI delimiting uses, the following can be safely used:
function fixedEncodeURIComponent(str) {
return encodeURIComponent(str).replace(/[!'()
]/g, function(c) {
return '%' + c.charCodeAt(0).toString(16);//toString(16)=16진수(base 16), 알파벳 f 까지 사용하여 표현하도록 한다.
});
}

encodeURI, encodeURIComponent에 들어있는 URI의 약자를 정리하며 이번 글을 마무리하고자 한다.
URI(Uniform Resource Identifier): 하나의 리소스를 가리키는 문자열. 가장 흔한 URI는 URL로, 웹 상에서의 위치로 리소스를 식별합니다.

출처:
https://developer.mozilla.org/ko/docs/Glossary/URI
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
https://stackoverflow.com/questions/31024779/typeerror-request-path-contains-unescaped-characters-how-can-i-fix-this/48535265

profile
바꿀 수 있는 것에 주목하자

0개의 댓글