URL 인코딩

지헌·2024년 9월 27일
0

URL 인코딩이란?

URL 인코딩은 웹에서 데이터를 안전하게 전송하기 위해 사용되는 퍼센트 인코딩 방식입니다. 이를 통해 URL에 사용할 수 없는 문자(공백, 특수 문자, 비아스키 문자 등)를 전송 가능한 형태로 변환하여 데이터의 손실이나 변조를 방지합니다. URL 인코딩은 URL의 구조를 유지하고, 서버 오류를 방지하는 역할을 합니다.

그 예시로 공백은 %20으로 표현되고, +는 %2B로 표현됩니다.

인코딩, 디코딩

인코딩 과정

  1. 문자 변환: URL에서 허용되지 않는 문자는 % 기호 뒤에 해당 문자의 ASCII 값을 16진수로 표현하여 대체됩니다.
    예: 공백( ) → %20, ! → %21
  2. 문자 집합: URL에서 사용할 수 있는 문자는 알파벳 대소문자, 숫자, 그리고 일부 특수 문자(-, _, ., ~)에 한정됩니다. 나머지 문자는 인코딩이 필요합니다.
  3. 쿼리 문자열 일 때는, 공백+로 변환되고 URL에서는 %20이면 공백으로 변환됩니다.

디코딩 과정

  1. 문자 복원: 인코딩된 문자열에서 % 기호와 그 뒤에 오는 두 자리 16진수 값을 찾아, 이를 ASCII 문자로 변환합니다.
    예: %20 → 공백( ), %21 → !
  2. 처리 방식: 일반적으로 프로그래밍 언어나 라이브러리에서 제공하는 함수나 메서드를 사용하여 디코딩을 수행합니다.
  3. 쿼리 문자열에서 +공백으로 변환되고 URL에서는 %2B이면 그대로 +로 변환됩니다.

?key1=value1&key2=value2&... (쿼리 문자열)
key = value (쿼리 파라미터)

인코딩, 디코딩 활용 예시

import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { AxiosError } from "axios";

import { basicAxios } from "@/api/axios";

const useOAuth2 = (provider: string) => {
  const navigate = useNavigate();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const startOAuth2Flow = () => {
    const redirectUri = encodeURIComponent("https://localhost(도메인주소)/login");
    let oauth2Url = "";

    if (provider === "google") {
      oauth2Url = `https://api.fordogs.store/oauth2/authorization/google?redirect_uri=${redirectUri}`;
    } else if (provider === "kakao") {
      oauth2Url = `https://api.fordogs.store/oauth/authorize/kakao?redirect_uri=${redirectUri}`;
    }

    if (oauth2Url) {
      window.location.href = oauth2Url;
    } else {
      setError("지원하지 않는 OAuth 제공자입니다.");
    }
  };

  useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search);
    const rawAuthCode = urlParams.get("code");

 
    const authCode = rawAuthCode ? rawAuthCode.replace(/ /g, "+") : null;


  // const formattedAuthCode = authCode ? decodeURIComponent(authCode) : null; 불디코딩 부분 제거

    const getJwtWithCode = async (code: string) => {
      try {
        setLoading(true);
        console.log("Auth Code:", code);

        const response = await basicAxios.post("/users/login-with-code", {
          authCode,
        });

        if (response.status === 201) {
          const { userId, accessToken, expirationTime } = response.data.result;

          localStorage.setItem("accessToken", accessToken.value);
          localStorage.setItem("userId", userId);
          localStorage.setItem("expirationTime", expirationTime);         localStorage.getItem("expirationTime")
          );

          navigate("/");
        }
      } catch (err) {
        const error = err as AxiosError;
        console.error("요청 오류:", error);
        if (error.response) {
          console.error("서버 응답 데이터:", error.response.data);
        }
        setError("로그인에 실패했습니다. 다시 시도해주세요.");
      } finally {
        setLoading(false);
      }
    };

    if (authCode) {
      getJwtWithCode(authCode);
    }
  }, [navigate, provider]);

  return {
    startOAuth2Flow,
    loading,
    error,
  };
};

export default useOAuth2;

해당 코드는 OAuth2 기능을 구현할 때 URL 쿼리 파라미터 값의 인코딩과 디코딩 과정을 해결하여 api에 값을 전달해준 코드입니다.

  1. window.location.search를 통해 code = URL 쿼리 파라미터값을 가져와서 쿼리 파라미터를 파싱합니다.이 때 쿼리 파라미터 값을 파싱할 때 자동으로 디코딩 작업이 수행되어서 +공백으로 변하는 작업이 이루어집니다.

  2. const authCode = rawAuthCode ? rawAuthCode.replace(/ /g, "+") : null; : 만약 공백이 있으면 +로 변환합니다.

  3. const formattedAuthCode = authCode ? decodeURIComponent(authCode) : null; : authCode가 존재하면 decodeURIComponent를 사용하여 다시 디코딩됩니다. %xx형식은 해당 기호로 변환해주고 +는 공백으로 변환해줍니다.(해당 코드는 URL 쿼리 파라미터 값을 가져올 때 자동으로 디코딩 되는 것을 공부하는 중간에 깨달아서 삭제했습니다.)
    ❓: 공백+로 replace 한 후 디코딩 과정에서 다시 공백이 안됐는지는 의문 -> Base64로 인코딩된 문자열 디코딩 했기 때문에 원래 데이터가 출력

결론은 플젝 친구에게 설명하기 위해서 시작한 공부와 URL 쿼리 파라미터의 자동 디코딩 문제로 인해 인코딩과 디코딩에 대해서 공부하면서 코드의 불필요한 부분을 찾게된 좋은 시간이였습니다.

후기. 서버에서 URL을 보낼 때 인코딩을 해서 보냈더라면 +가 공백으로 디코딩이 안되고 %2B로 오기 때문에 클라이언트에서는 +로 디코딩 되면 제대로 보내졌을거라는 토론이 오갔습니다.

profile
차곡차곡 그만 쌓아올리고 취업해서 부딪쳐보고 싶은

0개의 댓글