USECASE : 대만 ECPAY 편의점 픽업 지점 선택을 위한 Request the e-map of convenience store(B2C/C2C)
문서에 명시되어 있다시피,
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 로 던져주더라도, 프론트로 바로 받을 수 이뜸!!!!!
'programming > React' 카테고리의 다른 글
Auth.js signIn 완료 후 session 이 여전히 null (수동 리프레시를 해야만 session 이 업데이트 됨) (0) | 2024.10.30 |
---|---|
[Next.js] Google Map Distance Matrix API 프론트단에서 사용하기 (0) | 2024.08.21 |
Next.js App Router SSR 용 fetch 코드 (헤더 쿠키, Authorization 세팅) (0) | 2024.08.13 |
Next.js with Typescript 프로젝트 테스트 코드 작성하기(jest, testing-library/react) (0) | 2024.06.17 |
Next.js 에서 Client Side Fetch 를 React-Query + 기본 Fetch 조합으로 사용하기 (0) | 2024.05.29 |