[C#/ASP.NET] Server.UrlEncode() + 코드 리뷰
안녕하세요 코북입니다. 로그인 후 원래 페이지로 돌아오는 작업을 처리하면서 Url을 쿼리스트링 방식을 통해 넘겨줬습니다. 이때 변수/값 쌍에 모호함이 존재하여 계속 오류가 발생했습니다. 넘겨주는 Url값을 인코딩하고 다시 디코딩하는 방식을 사용하여 문제를 해결했습니다.
@Html.Raw(Server.UrlEncode("url")) 리뷰
▶ @Html
HTML객체를 렌더링하는 데 사용되는 HtmlHelper 객체입니다.
※ 렌더링 : 작성된 마크업 언어를 엔진이 해석해서 사람의 눈으로 볼 수 있도록 만들어(그려)주는 과정
▶ @Html.Raw()
HTML 코드를 인코딩하지 않은 원본 상태로 반환해줍니다.
<div>코북<br/>입니다</div>
<div>@Html.Raw(코북<br/>입니다)</div>
첫 번째는
코북
입니다
라고 반환되고
두 번째는
코북<br/>입니다
라고 반환됩니다.
▶ Server.UrlEncode()
숫자나 알파벳 문자가 아닌 것(0~9, a~z이 아닌 문자)을 아스키 헥사 코드로 변환시켜주는 메서드입니다. 이 메서드는 해당 문자를 16진수 아스키 코드로 변환시킨 후 그 앞에 %를 붙입니다. 빈 문자열은 + 기호로 변환됩니다. 예를 들어
ReturnUrl = "https://cobook.tistory.com/80"
이라는 문자열을 Server.UrlEncode() 메서드를 통해 다음과 같이 변경시킬 수 있다.
Server.UrlEncode(ReturnUrl)
https%3A%2F%2Fcobook.tistory.com%2F80
그렇다면 이 메서드는 언제 사용해야 하는 걸까??!
다음과 같은 경우를 살펴보자. 만약 어떤 URL에서 QueryString으로 원하는 값을 받으려고 할 때 다음과 같이 어떤 주소 값을 받아야 할 경우가 있다.
<a href="http://cobook.tistory.com/Login?URL=/Item/ItemDetail?idx=123123&item_code=C123125"></a>
위의 코드는 querystring으로 URL=/Item/ItemDetail?idx=123123&item_code=C123125 부분을http://cobook.tistory.com/Login 에 넘긴 경우입니다. 이때 ? 가 한 개는 Login 다음에, 다른 한 개는 Detail 다음에 총 2개 존재합니다. 그렇기 때문에 querystring을 캡처해오는데 모호함을 겪게 됩니다. 또한 & 표시를 기준으로 "변수이름/값"이 하나의 쌍으로 이루어진 querystring의 경우 URL=/Item/ItemDetail?idx=123123 과 item_code=C123125 라는 두 개의 변수이름/값 쌍이 존재하는 것으로 받아들일 수 있습니다. 하지만 URL주소를 생성한 사람은 URL이라는 변수에 /Item/ItemDetail?idx=123123&item_code=C123125 란 값이 들어 있는 하나의 변수이름/값 쌍을 염두에 두었을 것입니다. 따라서 이런 문제를 해결하기 위해 Server.UrlEncode를 사용할 수 가 있습니다.
이런 문제가 가장 빈번하게 발생하는 경우는 다음과 같은 경우입니다.
회원 인증을 거쳐야지만 어떤 페이지를 볼 수 있도록 한 사이트에서 로그인을 거치지 않은 사용자가 해당 페이지에 접근하려고 하면 먼저 로그인 페이지로 유도한 후 로그인을 했을 경우 원래 접근하려고 했던 페이지로 이동시켜주는 경우를 생각해 봅시다. 이럴 경우 로그인 페이지인 login.cshtml에 원래 접근하고자 했던 페이지가 있는 URL 주소를 querystring으로 넘겨줍니다. 이때 넘겨주는 URL에 Server.UrlEncode() 메서드를 사용하여 값을 넘겨주면 됩니다. Encoding된 데이터는 IIS에서 자동으로 변환해 주지만 HttpUtility.UrlDecode()를 통해 다시 디코딩하는 방법도 있습니다.
※ Server.UrlEncode(문자열) === HttpUtility.UrlEncode(문자열, Response.ContentEncoding)
▶ Location 객체
window.location === document.location
두 객체 모두 Location의 프로퍼티들을 사용할 수 있습니다.
ex)
document.location.href
window.location.href
▶ StringBuilder
StringBuilder가 일반적인 String 결합보다 추천되는 이유는 내부에 버퍼를 갖고 있고, 문자열에 변경이 있을 때마다 새로운 문자열을 생성하지 않고 버퍼의 내용을 변경하기 때문입니다. 다만 이 설명은 절반만 맞고 절반은 맞지 않습니다. StringBuilder 역시 내부 버퍼의 크기를 넘는 문자열이 추가되면 더 큰 크기의 버퍼를 할당하고, 기존 버퍼의 내용을 모두 복사하는 식으로 처리를 합니다. 즉, 경우에 따라서는 string 연결과 마찬가지로 문자열이 변경될 때마다 재할당이 일어나고, 기존의 버퍼는 버려져 가비지가 됩니다. 이것을 방지하기 위해서는 생성할 때 미리 충분한 크기의 영역을 확보해두면 됩니다. 예상되는 최종 출력 문자열의 크기를 미리 계산하여, 생성자에 넣어주거나 Capacity 속성을 통해 영역을 확보해 주면 재할당이 일어나지 않습니다.
사용 -> StringBuilder 객체에 Append 메서드로 문자열을 추가할 수 있고 AppendFormat() 메서드로 형식을 정할 수 있습니다. 이외에도 Remove(), Insert(), Replace(), Clear() 등 의 메서드가 존재합니다.
배운 점
쿼리스트링을 너무 기계적으로 사용했던 것 같다는 생각이 드는 시간이었습니다. 내가 보낸 값을 컴퓨터가 어떻게 받아들이고 처리하는지에 대해 더 많은 고민이 필요하며 그 값이 얼마나 명확하고 모호한지 좀 더 많은 고민을 해봐야 할 것 같습니다.
본 글은 아래 링크의 내용을 참고하여 학습한 내용을 나름대로 정리한 글임을 밝힙니다.
https://overworks.github.io/unity/2018/08/30/finding-best-string-concatenation.html
https://namu.wiki/w/%EB%A0%8C%EB%8D%94%EB%A7%81#s-3