WeChat 브라우저 환경 결제 연동 개요
모바일 웹 환경(H5) 에서 WeChat 내부 결제를 수행하려면 사용자의 OpenID 확보와 JSBridge 를 통한 결제 요청 전송이 필수적입니다. 일반적으로 Vue 프레임워크를 기반으로 하더라도 WeChat 특유의 인증 프로세스를 먼저 통과해야 하며, 이후 서버 측에서 발급받은 결제 토큰을 사용하여 정산 흐름을 시작합니다.
1. 사용자 인증 및 OpenID 획득 전략
초기 진입 시 로컬 저장소에 저장된 인증 식별자가 존재하는지 확인해야 합니다. 식별자가 누락된 경우 WeChat 공개 플랫폼 API 를 통해 OAuth 인증 절차를 재개행하고, 성공적으로 반환된 정보를 캐시합니다. 현대적인 자바스크립트 표준인 URLSearchParams 를 활용하여 쿼리 파라미터 처리를 개선했습니다.
// 컴포넌트 마운트 시 인증 상태 검증
<span class="keyword">async verifyAuthorizationStatus() </span>{
const existingId = localStorage.getItem('wechat_user_uid');
if (!existingId || existingId === 'null') {
await <span class="keyword">this</span>.initWechatOAuthFlow();
}
}
<span class="keyword">async initWechatOAuthFlow() </span>{
const paramParser = new URLSearchParams(window.location.search);
const accessCode = paramParser.get('code');
const currentPath = window.location.href;
if (!accessCode) {
// 코드 미발견 시 WeChat 인증 센터로 리디렉션
const configAppId = process.env.VUE_APP_WECHAT_APPID;
const oauthUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${configAppId}&redirect_uri=${encodeURIComponent(currentPath)}&response_type=code&scope=snsapi_base#wechat_redirect`;
window.location.href = oauthUrl;
} else {
// 코드가 있을 때 백엔드 호출을 통해 실제 ID 변환
await <span class="keyword">this</span>.exchangeCodeForUid(accessCode);
}
}
<span class="keyword">async exchangeCodeForUid(code) </span>{
try {
const response = await httpClient.post('/api/auth/wechat-uid', { code });
if (response.data.success) {
localStorage.setItem('wechat_user_uid', response.data.uid);
}
} catch (error) {
console.error('인증 실패', error);
}
}
2. WeChat JSBridge 를 통한 결제 트리거
결제 요청은 반드시 WeChat 브라우저 내에서만 동작하며, WeixinJSBridge 객체의 invoke 메서드를 사용합니다. 필요한 결제 파라미터들은 서버 측 사전 결제 인터페이스를 통해 생성된 데이터를 클라이언트로 전달받아 주입해야 합니다.
<span class="keyword">const executeMobilePayment(paymentData) </span> {
const { appId, timeStamp, nonStr, signString, prePayId } = paymentData;
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
appId: appId,
timeStamp: timeStamp,
nonceStr: nonStr,
package: 'prepay_id=' + prePayId,
signType: 'RSA',
paySign: signString
},
(response) => {
switch (response.err_msg) {
case 'get_brand_wcpay_request:ok':
showNotification('결제가 완료되었습니다.', 'success');
router.push({ path: '/payment/result' });
break;
case 'get_brand_wcpay_request:fail':
showNotification('결제 중 오류가 발생했습니다.', 'error');
break;
case 'get_brand_wcpay_request:cancel':
showNotification('사용자가 결제를 취소했습니다.', 'warning');
break;
}
}
);
}