본문 바로가기

programming/React

프론트에서 (Next.js) 에서 POST FormData 응답 받기 (ECPAY)

USECASE : 대만 ECPAY 편의점 픽업 지점 선택을 위한 Request the e-map of convenience store(B2C/C2C)

 

[ECPAY 개발문서]

 

문서에 명시되어 있다시피,

HTTPS Transfer Protocol

HTTP Method:POST
Accept:text/html
Content Type:application/x-www-form-urlencoded

 

form 형태로, POST 로 게다가 <html> 텍스트로 데이터를 요청/응답 받아야한다.

 

 

프론트에서 Request 파라미터를 말아서 form 으로 보내고, 

Request 파라미터 중 하나인 "ServerReplyURL" 키에 어떤 값을 담아 보내야 하는지가 고민이었다.

 

왜냐하면, ServerReplyURL 이 url 은, 편의점을 선택하는 ecpay.map 화면으로 url 이 이동 되었다가, 

유저가 편의점 선택을 완료하여 제출하고 나서

1. 다시 돌아올 mysite 페이지

2. POST 로 쏴주는 응답 데이터를 받을 엔드 포인트 

 

이 두가지 역할을 해야하기 때문이다.

 

 

하지만, Next.js 를 사용하고 있어서, 프론트에서도 POST 요청을 받을 수 있는 엔드포인트를 만들 수 있다.

 

1. app 밑에 api 라우트 파일 생성

/app/api/checkout/cvs-result/route.ts 

import { NextResponse } from "next/server";

// ECPAY 편의점 선택 결과 리턴 엔드 포인트
export async function POST(request: Request) {
  const url = new URL(request.url);

  const body = await request.text();
  return NextResponse.redirect(`https://mysite.com/checkout?${body}`);
}

 

 

2. 편의점 선택 컴포넌트 생성

/components/SelectConvenience.tsx

 

 

SelectConvenience 컴포넌트는, 편의점 종류를 버튼으로 제공하고,

특정 편의점 버튼을 눌러서 선택하면,

ecpay 에 지점 선택을 위한 map 페이지를 요청하는 컴포넌트 이다.

 

편의점 종류 선택지 버튼을 UI 로 제공하고,

form 을 숨겨서 submit 할 수 있도록 하였다.

 

ECPAY 로 보내는 request parameter 에

필수 파라미터 정보를 세팅하고,

ServerReplyUrl = "https://mysite.com/api/checkout/cvs-result" 로 뚫어 놓은 API 주소를 세팅한다

export default function SelectConvenience() {
  const [selectedConvenience, setSelectedConvenience] = useState(pickUpInfo?.selectedConvenience ?? "");

  const onSelectCvs = (cvsType: string) => {
    setSelectedConvenience(cvsType);
    setTimeout(() => {
      const formElement = document.getElementById("cvsForm") as HTMLFormElement;
      if (formElement) formElement?.submit();
    }, 0);
  };

  return (
    <>
      <div className="flex gap-[12px] mobile:flex-col">
        <button onClick={() => onSelectCvs("UNIMARTC2C")}>
          Seven Eleven
        </button>
        <button onClick={() => onSelectCvs("FAMIC2C")}>
          Family Mart
        </button>
      </div>

      <form
        action="https://logistics.ecpay.com.tw/Express/map"
        method="POST"
        encType="application/x-www-form-urlencoded"
        id="cvsForm"
      >
        <input type="hidden" name="MerchantID" value={process.env.NEXT_PUBLIC_MERCHANT_ID ?? ""} />
        <input type="hidden" name="LogisticsType" value="CVS" />
        <input type="hidden" name="LogisticsSubType" value={selectedConvenience} />
        <input type="hidden" name="IsCollection" value="N" />
        <input type="hidden" name="MerchantTradeNo" value='20241023094324' />
        <input
          type="hidden"
          name="ServerReplyURL"
          value={`https://mysite.com/api/checkout/cvs-result`}
        />
      </form>
    </>
  );
}

 

 

3. 요청 form을 전송

편의점 종류 버튼을 누르면, 숨겨져있던 form 이 제출되면서, mysite.com 이었던 화면이 ecpay map 화면으로 url 이 이동된다.

 

 

ecpay 가 제공하는 Map 사이트로 이동되어 유저는 특정 지점을 선택할 수 있다

 

 

4. ecpay 에서 제공하는 site 에서 유저가 편의점을 선택하고 완료를 누르면,

ecpay 는 ServerReplyURL 파라미터 값으로 받은 url 로 formData 형식으로 응답값을 POST 로 쏜다.

이로 인해서, 유저 브라우저 화면은 "https://mysite.com/api/checkout/cvs-result" 로 이동

하지만, 프론트에는 해당 페이지가 없음!

페이지는 없고, api 라우트만 존재!

 

화면상에는 페이지 없음이 뜨고, 

뚫어 놓은 api POST 라우트로 응답 데이터가 들어온다.

 

 

5. 이 데이터를 쿼리 파라미터로 말아서, 다시 원래 화면으로 리다이렉트 시킨다

1번에서 만들어 둔 route 에서 다음과 같이 redirect 를 시킨다

return NextResponse.redirect(`https://mysite.com/checkout?${body}`);

 

ECPAY 가 리턴 시킨 "https://mysite.com/api/checkout/cvs-result" 로는 잠시 이동했지만, 

바로 Next 의 /api/checkout/cvs-result 라우트에서 페이지를 리다이렉트 시키기 때문에,

육안으로 감지 할 수 없는, 페이지 이동이 발생한다

 

6. 유저 화면의 Url 이 변경된다!

 

 

 

Next 에서 api 라우트를 제공하면서, CORS 이슈로 백엔드 서버에서 일일히 API 를 따로 만들어 주어야 했던 것들을 
바로 프론트에서 진행 할 수 있게 된 것들이 많다.
서드파티 API 에서 응답을 POST 로 던져주더라도, 프론트로 바로 받을 수 이뜸!!!!!