본문 바로가기
FrontEnd

React Router를 활용한 Toss Payments Redirect 처리

by E_van 2022. 10. 12.

Toss Payments를 사용하는 프로젝트에서는 결제 성공/실패 후 Redirect URL로 사용자를 안내해야 합니다. 이 과정에서 URL 파라미터를 통해 결제 상태를 전달받아 처리하고, 적절한 페이지로 리디렉션하는 로직을 구현할 수 있습니다.

아래는 Toss Payments의 성공 및 실패 Redirect 처리 컴포넌트를 구현하는 방법과 관련된 내용을 설명합니다.


1. Redirect URL 설정

Toss Payments 요청 시 successUrl과 failUrl을 설정합니다. 이 URL로 결제 성공 또는 실패 후 리디렉션됩니다.

tossPayment.requestPayment('카드', {
    amount: productAmount,
    orderId: id,
    orderName: name,
    customerName: userName,
    successUrl: `${url}/payment/success`, // 성공 시 Redirect
    failUrl: `${url}/payment/fail`,      // 실패 시 Redirect
});

2. 실패 Redirect 처리 컴포넌트

/payment/fail 경로에서 결제 실패를 처리하는 로직입니다. URL 파라미터에서 상태를 가져와 SweetAlert로 사용자에게 안내하고, 이후 적절한 페이지로 리디렉션합니다.

TossRedirectFailHandler 구현

import React, { useEffect } from "react";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import Swal from "sweetalert2";

const TossRedirectFailHandler = () => {
    const { id } = useParams();
    const nav = useNavigate();
    const location = useLocation();

    useEffect(() => {
        const urlParams = new URL(window.location.href).searchParams;
        const code = urlParams.get('code');
        const message = urlParams.get('message');

        if (code === 'PAY_PROCESS_CANCELED') {
            Swal.fire({
                title: '결제가 취소되었습니다.',
                text: '사용자가 결제를 취소하였습니다.',
                icon: 'info',
                confirmButtonText: '확인',
                confirmButtonColor: '#0EAD0E',
            }).then(() => {
                if (location.pathname === "/payment/fail") {
                    nav('/cart'); // 장바구니 페이지로 이동
                }
            });
        } else {
            Swal.fire({
                title: '결제 오류 발생',
                text: `오류 코드: ${code}\n오류 메시지: ${message}`,
                icon: 'error',
                confirmButtonText: '확인',
                confirmButtonColor: '#FF0000',
            }).then(() => {
                nav('/cart');
            });
        }
    }, [location, nav]);

    return null; // 화면에 표시할 내용이 없는 처리용 컴포넌트
};

export default TossRedirectFailHandler;

3. 성공 Redirect 처리 컴포넌트

/payment/success 경로에서 결제 성공을 처리하는 로직입니다. 결제 완료 데이터를 서버로 전달하고, SweetAlert를 사용해 사용자에게 결제 완료 메시지를 표시합니다.

TossRedirectHandler 구현

import React, { useEffect } from "react";
import axios from '@/lib/GlobalAxios';
import { useNavigate, useLocation, useParams } from "react-router-dom";
import Swal from "sweetalert2";

const TossRedirectHandler = () => {
    const { id } = useParams();
    const nav = useNavigate();
    const location = useLocation();

    useEffect(() => {
        const urlParams = new URL(window.location.href).searchParams;
        const orderId = urlParams.get('orderId');
        const paymentKey = urlParams.get('paymentKey');
        const amount = urlParams.get('amount');

        axios.post(`/api/v1/order/payment`, {
            orderId,
            paymentKey,
            amount,
        })
        .then(response => {
            if (response.data.result_data.error_code === 0) {
                axios.get(`/api/v1/user`).then(userResponse => {
                    Swal.fire({
                        title: '결제 완료',
                        text: '결제가 성공적으로 완료되었습니다.',
                        icon: 'success',
                        confirmButtonText: '닫기',
                        confirmButtonColor: '#0EAD0E',
                    }).then(() => {
                        nav('/order_history'); // 주문 내역 페이지로 이동
                    });
                });
            } else {
                handlePaymentError(response.data.result_data.error_code);
            }
        }).catch(error => {
            console.error('결제 처리 오류:', error);
        });
    }, [nav]);

    const handlePaymentError = (errorCode) => {
        let errorMessage = '알 수 없는 오류가 발생했습니다.';
        if (errorCode === '-1') errorMessage = '필수 파라미터가 부족합니다.';
        if (errorCode === '-2') errorMessage = '주문 정보를 찾을 수 없습니다.';
        if (errorCode === '-3') errorMessage = '결제 승인에 실패했습니다.';

        Swal.fire({
            title: '결제 오류',
            text: errorMessage,
            icon: 'error',
            confirmButtonText: '확인',
            confirmButtonColor: '#FF0000',
        }).then(() => {
            nav(`/cart`, { state: { payment: 'fail' } });
        });
    };

    return null; // 화면에 표시할 내용이 없는 처리용 컴포넌트
};

export default TossRedirectHandler;

4. 라우팅 설정

React Router를 사용하여 /payment/success와 /payment/fail 경로를 설정합니다.

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import TossRedirectHandler from '@/components/TossRedirectHandler';
import TossRedirectFailHandler from '@/components/TossRedirectFailHandler';

export default function Router() {
    const routes = useRoutes([
        { path: 'payment/success',element: <TossRedirectSuccessHandler /> },
        { path: 'payment/fail', element: <TossRedirectFailHandler /> },
    ]);
	return createBrowserRouter(routes);
}

요약

  • 성공/실패 Redirect URL 설정 시 successUrl과 failUrl을 지정합니다.
  • TossRedirectFailHandler는 결제 실패 시 오류 메시지를 보여주고, 적절한 페이지로 리디렉션합니다.
  • TossRedirectHandler는 결제 성공 후 서버와 통신하고, SweetAlert를 통해 사용자에게 결제 성공 메시지를 표시합니다.
  • React Router로 Redirect 경로를 설정하여 동작을 연결합니다.