개인 프로젝트(3)

윤준상·2025년 3월 18일
0
post-thumbnail

하..이번에 정말 가고싶고 나의 긍정적인 마인드를 선보일 수 있는 기업에 지원했는데 지원자수도 너무 많고, 서류열람만 되고 또 연락안올거 같아서 우울할거 같아서 오예스 하나를 먹고 버텼다.. 오예스랑 칙촉 너무 맛있는듯; 오늘 등 운동도 하고 도서관가서 할 것도 하고 내일은 오늘보다 더 나은 내가 되어야겠다!!

카카오페이 결제 승인 오류 해결 과정

문제 발생

카카오페이 결제 API를 연동하는 과정에서 결제 요청(Ready) → 결제 승인(Approve) 순서로 진행해야 하지만, 결제 승인 과정에서 아래와 같은 오류가 발생했다.

발생한 오류:

pg_token이 백엔드로 전달되지 않음

프론트에서는 URL에 pg_token이 포함되어 있었지만, 백엔드에서는 해당 값을 받지 못하고 MissingServletRequestParameterException이 발생.
백엔드에서 System.out.println 로그가 찍히지 않음

정상적인 API 호출이 이루어지지 않았을 가능성이 있음.
프론트에서 결제 승인 요청을 보냈으나 실패

프론트에서 백엔드 /payment/success 엔드포인트로 pg_token, postId, tid를 전달했지만, 응답이 400(Bad Request) 또는 오류 메시지가 발생함.

원인 분석

  1. pg_token이 프론트에서 잘 전달되고 있는지 확인
  • console.log를 추가하여 프론트에서 pg_token, postId, tid가 올바르게 찍히는지 확인했다.
  • 결과적으로, 프론트에서는 정상적으로 URL에서 pg_token을 추출하고 있었음.
  1. 백엔드에서 요청을 올바르게 받고 있는지 확인
  • System.out.println("Received pg_token: " + pgToken); 추가했으나 콘솔에서 찍히지 않았음.
  • 즉, 프론트에서 백엔드로 요청이 제대로 가지 않았을 가능성이 높음.
  1. Axios 요청의 Content-Type 문제
  • axios.post(...) 요청 시, headers: { Authorization: Bearer ${token} }에서 Bearer를 백틱을 사용한 템플릿 리터럴로 감싸는 대신, 일반적인 문자열로 사용해야 함.
  1. pg_token 전달 방식 문제
  • axios.post 요청을 보낼 때, params를 body로 보냈기 때문에 Spring에서 @RequestParam으로 받을 수 없었음.
  • 백엔드에서 @RequestParam 대신 @RequestBody를 사용해야 하거나, 프론트에서 올바르게 params로 전달해야 함.

해결 방법

프론트 수정
1. pg_token, postId, tid를 정상적으로 백엔드로 전송하도록 수정
2. Bearer 토큰을 올바르게 전달하도록 수정
3. 요청 데이터를 query params가 아니라 body로 보내도록 수정

수정된 프론트 코드 (PaymentSuccess.js)

import React, { useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import axios from "axios";

const PaymentSuccess = () => {
    const [searchParams] = useSearchParams();
    const navigate = useNavigate();

    useEffect(() => {
        const pgToken = searchParams.get("pg_token");
        const postId = searchParams.get("postId");
        const tid = localStorage.getItem("tid");
        const token = localStorage.getItem("token");

        console.log("URL:", window.location.href);
        console.log("pg_token:", pgToken);
        console.log("postId:", postId);
        console.log("tid:", tid);

        if (!pgToken || !postId || !tid) {
            alert("결제 정보가 올바르지 않습니다.");
            navigate("/");
            return;
        }

        axios
            .post(
                `http://localhost:8080/payment/success`,
                { pg_token: pgToken, postId: postId, tid: tid },
                {
                    headers: {
                        Authorization: `Bearer ${token}`,
                        "Content-Type": "application/json",
                    },
                }
            )
            .then(() => {
                alert("결제가 완료되었습니다!");
                localStorage.removeItem("tid");
                navigate(`/post/${postId}`);
            })
            .catch((error) => {
                console.error("결제 승인 실패:", error.response ? error.response.data : error);
                alert("결제 승인에 실패했습니다.");
                navigate("/");
            });
    }, [searchParams, navigate]);

    return <div>결제 승인 중...</div>;
};

export default PaymentSuccess;

백엔드 수정
1. System.out.println을 사용하여 요청을 받는지 확인
2. 프론트에서 전달하는 방식에 맞게 @RequestParam을 @RequestBody로 변경
3. 카카오페이 승인 API 호출 시, 올바른 헤더를 전달하도록 수정

수정된 백엔드 코드 (PaymentController.java)

@PostMapping("/success")
public ResponseEntity<String> paymentSuccess(
        @RequestBody Map<String, String> requestData,
        @RequestHeader("Authorization") String token) {

    String pgToken = requestData.get("pg_token");
    Long postId = Long.valueOf(requestData.get("postId"));
    String tid = requestData.get("tid");

    System.out.println("Received pg_token: " + pgToken);
    System.out.println("Received postId: " + postId);
    System.out.println("Received tid: " + tid);

    try {
        String email = jwtTokenProvider.getUserEmail(token.replace("Bearer ", ""));
        Long userId = userService.getUserIdByEmail(email);

        kakaoPayService.approvePayment(postId, userId, tid, pgToken);

        return ResponseEntity.ok("결제가 성공적으로 완료되었습니다.");
    } catch (Exception e) {
        System.out.println("결제 승인 오류 발생: " + e.getMessage());
        e.printStackTrace();
        return ResponseEntity.badRequest().body("결제 승인 중 오류 발생: " + e.getMessage());
    }
}

카카오페이 리다이렉트 설정 추가

카카오 디벨로퍼에서 결제 승인, 실패, 취소 리다이렉트 URL 설정 필요.
초기 설정 누락으로 승인 요청 실패함..^^ 바보

설정 경로:
카카오 디벨로퍼 → 애플리케이션 → 플랫폼

결론

주요 원인

  • pg_token이 query parameter로 전달되지 않아 백엔드에서 제대로 받지 못함.
  • axios.post 요청 시 @RequestParam이 아닌 @RequestBody로 데이터를 보내야 함.
  • Bearer 토큰 전달 방식이 잘못되어 인증 문제 발생 가능성.

해결 방법

  • @RequestBody로 데이터 받기.
  • axios.post 요청 시 headers를 올바르게 설정.
  • console.log와 System.out.println을 적극 활용하여 디버깅.
profile
흘러가되 원하는 방향으로

0개의 댓글