본 글은 주로 위챗 결제 개발 과정에 대한 관련 정보를 소개하고 있으니, 필요하신 분들은 참고하시면 됩니다.
참고로 저는 모바일 앱과 관련된 위챗 오픈 플랫폼 결제를 사용하고 있습니다. 그리고 그 계정은 대중과 관련이 없습니다.
위챗 결제 주요 동작 과정
1. 사용자가 앱을 탐색한 후 상품을 선택하고 주문합니다.
2. 서버는 주문 로직을 처리하고 정식 결제 프로세스를 시작합니다
3. 먼저 백엔드 서버는 토큰을 얻기 위해 weixin 서버에 요청을 시작합니다.
4. 백엔드 서버는 토큰을 가져와서 다른 매개변수로 암호화한 후 다시 weixin 서버에 요청을 보내 선불 ID를 얻습니다.
5. 백엔드 서버가 선불 ID를 반환합니다. 앱 클라이언트
6. 앱이 휴대폰의 WeChat제어를 호출하여 결제 프로세스를 완료합니다.
7.app은 백엔드 서버에 콜백 요청을 시작하여 서버에 트랜잭션이 완료되었음을 알립니다.
8. weixin 서버는 모든 프로세스를 처리한 후 백엔드 서버에 게시 요청을 시작하여 백엔드 서버에 거래가 완료되었음을 공식적으로 알립니다
위 과정 중 일부 참고:
1. 매번 획득하는 토큰에는 시간 제한이 있으며, 기본값은 7200초이며, 하루에 최대 200회 획득할 수 있으므로 redis캐시에 넣고 만료된 후 다시 검색하는 것이 가장 좋습니다
2. 앱에서 시작된 콜백은 기본적으로 신뢰할 수 없습니다. WeChat 서버에 대한 쿼리 주문을 시작하는 것이 가장 좋지만(반드시 그런 것은 아님), 이 거래의 결과를 확인하세요.
3. weixin 서버에 의해 백그라운드로 시작된 notify는 거래 완료를 보장하는 최종 장벽입니다. 백그라운드 서버는 확인 후 "성공"을 반환해야 합니다. 그렇지 않으면 weixin 서버가 요청을 다시 보내려고 시도합니다.
토큰 가져오기
이 단계는 매우 간단합니다. 가져오기 요청을 보내기만 하면 됩니다. 올바른 매개변수를 구성하기만 하면 됩니다.
rreee선불 받기
WeChat 결제 개발 과정에서 가장 지루한 일은 선불을 받는 것입니다.
이 단계에서는 다음 매개변수를 어셈블해야 합니다.
‘‘‘从微信服务器获取token‘‘‘ def _getAccessTokenFromWeixin(self): response = requests.get(self.tokenUrl % (self.appId, self.appSecret)) if response.status_code == 200: text = response.text tokenInfo = json.loads(text) try: token = tokenInfo[‘access_token‘] expires_in = tokenInfo[‘expires_in‘] self._writeWeixinTokenLog(token, self.order_no) return token except KeyError: return None #token获取失败 return None #http请求失败
패키지 어셈블
여기 첫 번째 단계는 패키지를 조립하는 것입니다:
{ "appid":"wxd930ea5d5a258f4f", "traceid":"test_1399514976", "noncestr":"e7d161ac8d8a76529d39d9f5b4249ccb ", "timestamp":1399514976, "package":"bank_type=WX&body=%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF% 95&fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fweixin.qq.com&out_trade_ no=7240b65810859cbf2a8d9f76a638c0a3&partner=1900000109&spbill_create_ip=196.168.1.1& total_fee=1&sign=7F77B507B755B3262884291517E380F8", "sign_method":"sha1", "app_signature":"7f77b507b755b3262884291517e380f8" }
패키지를 조립하는 데 필요한 매개변수는 위의 코드와 같으므로 다음을 준비해야 합니다. params를 준비한 후 서명 및 서명 프로세스를 다음과 같이 준비합니다.
1. 키의 사전 순서에 따라 params를 정렬한 다음 string으로 연결합니다.
기호를 포함하지 마십시오. 2. 위의 Splice key=paternerKey 에서 문자열 뒤에 md5 서명을 수행한 다음 이를 대문자로 변환합니다. 서명
을 입력하고 모든 매개변수의 값을 urlencode합니다. 이를 변환한 다음 sign=signValue로 연결하여 패키지 문자열을 가져옵니다.
여기서 MD5를 만드는 과정은 다음과 같습니다.
"package":"bank_type=WX&body=%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF% 95&fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fweixin.qq.com&out_trade_ no=7240b65810859cbf2a8d9f76a638c0a3&partner=1900000109&spbill_create_ip=196.168.1.1& total_fee=1&sign=7F77B507B755B3262884291517E380F8",
패키지를 조립하는 코드:
def createMD5Signature(self, signParams): ‘‘‘先排序‘‘‘ sortedParams = sorted(signParams.iteritems(), key=lambda d:d[0]) ‘‘‘拼接‘‘‘ stringSignTemp = "&".join(["%s=%s" % (item[0], item[1]) for item in sortedParams if item[0] != ‘sign‘ and ‘‘ != item[1]]) #加上财付通商户权限密钥 stringSignTemp += ‘&key=%s‘ % (self.partnerKey) #使用MD5进行签名,然后转化为大写 stringSign = hashlib.md5(stringSignTemp).hexdigest().upper() #Upper return stringSign
계속 매개변수 조립
패키지를 가져온 후 계속해서 매개변수를 조립합니다.
여기에 필요한 매개변수
def getPackage(self, packageParams): ‘‘‘先获取params的sign,然后将params进行urlencode,最后拼接,加上sign‘‘‘ sign = self.createMD5Signature(packageParams) packageParams = sorted(packageParams.iteritems(), key=lambda d:d[0]) stringParams = "&".join(["%s=%s" % (item[0], urllib.quote(str(item[1]))) for item in packageParams]) stringParams += ‘&sign=%s‘ % (sign) return stringParams
traceid=test_1399514976
여기에 구멍이 있다는 점에 유의하세요.
위의 매개변수 은 서명에 관여하지만 마지막 매개변수에 appKey가 포함되어 있지 않으므로 서명 후 삭제하는 것을 잊지 마세요.
1. 모든 매개변수를 사전순으로 정렬한 후
2. sha1을 서명하고 위 문자열 끝에 연결합니다
3. 여기에서 appKey를 삭제하고 서명을 추가하세요
sha1 서명을 얻는 코드는 다음과 같습니다.
appid=wxd930ea5d5a258f4f appkey=L8LrMqqeGRxST5reouB0K66CaY A WpqhA Vsq7ggKkxHCOastWksvuX1uvmvQcl xaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K noncestr=e7d161ac8d8a76529d39d9f5b4249ccb package=bank_type=WX&body=%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%95 &fee_type=1&input_charset=UTF-8¬ify_url=http%3A%2F%2Fweixin.qq.com&out_trade_no =7240b65810859cbf2a8d9f76a638c0a3&partner=1900000109&spbill_create_ip=196.168.1.1&tot al_fee=1&sign=7F77B507B755B3262884291517E380F8 timestamp=1399514976
그러면 다음과 같은 결과가 나옵니다. 매개변수:
def createSHA1Signature(self, params): ‘‘‘先排序,然后拼接‘‘‘ sortedParams = sorted(params.iteritems(), key=lambda d:d[0]) stringSignTemp = "&".join(["%s=%s" % (item[0], item[1]) for item in sortedParams]) stringSign = hashlib.sha1(stringSignTemp).hexdigest() return stringSign
선불 결제
코드는 다음과 같습니다:
{ "appid":"wxd930ea5d5a258f4f", "noncestr":"e7d161ac8d8a76529d39d9f5b4249ccb", "package":"Sign=WXpay"; "partnerid":"1900000109" "prepayid":"1101000000140429eb40476f8896f4c9", "sign":"7ffecb600d7157c5aa49810d2d8f28bc2811827b", "timestamp":"1399514976" }
우리가 받은 선불 형식은 다음과 같아야 합니다:
{"prepayid":"1101000000140429eb40476f8896f4c9","errcode":0,"errmsg":"Success"}
다시 서명
위의 sha1 서명 방법을 사용하여 다시 서명하고 다음 매개변수를 얻습니다.
‘‘‘获取预支付prepayid‘‘‘ def gerPrepayId(self, token, requestParams): ‘‘‘将参数,包括package,进行json化,然后发起post请求‘‘‘ data = json.dumps(requestParams) response = requests.post(self.gateUrl % (token), data=data) if response.status_code == 200: text = response.text text = json.loads(text) errcode = text[‘errcode‘] if errcode == 0: return text[‘prepayid‘] return None
백그라운드 서버는 결과를 앱에 반환합니다. 이때 앱은 결제를 시작할 수 있습니다.
위 프로세스 코드는 다음과 같습니다.
{ "appid":"wxd930ea5d5a258f4f", "noncestr":"e7d161ac8d8a76529d39d9f5b4249ccb", "package":"Sign=WXpay"; "partnerid":"1900000109" "prepayid":"1101000000140429eb40476f8896f4c9", "sign":"7ffecb600d7157c5aa49810d2d8f28bc2811827b", "timestamp":"1399514976" }
백그라운드 비동기 알림
WeChat 서버에서 전송 비동기 알림은 결제 성공의 최종 신호입니다. 이 단계는 안전입니다. 안전을 위해 서명을 확장해야 합니다.
확장 코드는 다음과 같습니다.
‘‘‘接收app的请求,返回prepayid‘‘‘ class WeixinRequirePrePaidHandler(BasicTemplateHandler): ‘‘‘这个方法在OrdersAddHandler中被调用‘‘‘ @staticmethod def getPrePaidResult(order_no, total_pay, product_name, client_ip): ‘‘‘封装了常用的签名算法‘‘‘ weixinRequestHandler = WeixinRequestHandler(order_no) ‘‘‘收集订单相关信息‘‘‘ addtion = str(random.randint(10, 100)) #产生一个两位的数字,拼接在订单号的后面 out_trade_no = str(order_no) + addtion order_price = float(total_pay) #这里必须允许浮点数,后面转化成分之后转化为int #order_price = 0.01 #测试 remote_addr = client_ip #客户端的IP地址 print remote_addr current_time = int(time.time()) order_create_time = str(current_time) order_deadline = str(current_time + 20*60) ‘‘‘这里的一些参数供下面使用‘‘‘ noncestr = hashlib.md5(str(random.random())).hexdigest() timestamp = str(int(time.time())) pack = ‘Sign=WXPay‘ ‘‘‘获取token‘‘‘ access_token = weixinRequestHandler.getAccessToken() logging.info("get token: %s" % access_token) if access_token: ‘‘‘设置package参数‘‘‘ packageParams = {} packageParams[‘bank_type‘] = ‘WX‘ #支付类型 packageParams[‘body‘] = product_name #商品名称 packageParams[‘fee_type‘] = ‘1‘ #人民币 fen packageParams[‘input_charset‘] = ‘GBK‘ #GBK packageParams[‘notify_url‘] = config[‘notify_url‘] #post异步消息通知 packageParams[‘out_trade_no‘] = str(out_trade_no) #订单号 packageParams[‘partner‘] = config[‘partnerId‘] #商户号 packageParams[‘total_fee‘] = str(int(order_price*100)) #订单金额,单位是分 packageParams[‘spbill_create_ip‘] = remote_addr #IP packageParams[‘time_start‘] = order_create_time #订单生成时间 packageParams[‘time_expire‘] = order_deadline #订单失效时间 ‘‘‘获取package‘‘‘ package = weixinRequestHandler.getPackage(packageParams) ‘‘‘设置支付参数‘‘‘ signParams = {} signParams[‘appid‘] = config[‘appId‘] signParams[‘appkey‘] = config[‘paySignKey‘] #delete signParams[‘noncestr‘] = noncestr signParams[‘package‘] = package signParams[‘timestamp‘] = timestamp signParams[‘traceid‘] = ‘mytraceid_001‘ ‘‘‘生成支付签名‘‘‘ app_signature = weixinRequestHandler.createSHA1Signature(signParams) ‘‘‘增加不参与签名的额外参数‘‘‘ signParams[‘sign_method‘] = ‘sha1‘ signParams[‘app_signature‘] = app_signature ‘‘‘剔除appKey‘‘‘ del signParams[‘appkey‘] ‘‘‘获取prepayid‘‘‘ prepayid = weixinRequestHandler.gerPrepayId(access_token, signParams) if prepayid: ‘‘‘使用拿到的prepayid再次准备签名‘‘‘ pack = ‘sign=WXPay‘ prepayParams = {} prepayParams[‘appid‘] = config[‘appId‘] prepayParams[‘appkey‘] = config[‘paySignKey‘] prepayParams[‘noncestr‘] = noncestr prepayParams[‘package‘] = pack prepayParams[‘partnerid‘] = config[‘partnerId‘] prepayParams[‘prepayid‘] = prepayid prepayParams[‘timestamp‘] = timestamp ‘‘‘生成签名‘‘‘ sign = weixinRequestHandler.createSHA1Signature(prepayParams) ‘‘‘准备输出参数‘‘‘ returnParams = {} returnParams[‘status‘] = 0 returnParams[‘retmsg‘] = ‘success‘ returnParams[‘appid‘] = config[‘appId‘] returnParams[‘noncestr‘] = noncestr returnParams[‘package‘] = pack returnParams[‘prepayid‘] = prepayid returnParams[‘timestamp‘] = timestamp returnParams[‘sign‘] = sign returnParams[‘partnerId‘] = config[‘partnerId‘] returnParams[‘addtion‘] = addtion else: ‘‘‘prepayid获取失败‘‘‘ returnParams = {} returnParams[‘status‘] = -1 returnParams[‘retmsg‘] = ‘prepayid获取失败‘ else: ‘‘‘token获取失败‘‘‘ returnParams = {} returnParams[‘status‘] = -1 returnParams[‘retmsg‘] = ‘token获取失败‘ ‘‘‘生成json格式文本,然后返回给APP‘‘‘ return returnParams
전체 과정은 다음과 같습니다.
def isTenpaySign(self, params): helper = WeixinRequestHandler() sign = helper.createMD5Signature(params) return params[‘sign‘] == sign
마지막으로 사용자가 휴대폰으로 결제를 완료하면 결제가 성공한 것으로 간주되지 않습니다. 이때 Weixin 서버가 알림 알림을 통해 반환된 성공을 받아야만 거래가 성공한 것으로 간주됩니다. 공식 WeChat 메시지를 받을 수 있습니다.
위는 WeChat 결제 개발 과정에 대한 정보를 모아 놓은 것입니다. 앞으로도 관련 정보를 계속 추가하겠습니다.
위 내용은 WeChat Pay의 개발 과정에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!