Maison >Applet WeChat >Développement WeChat >Introduction détaillée au processus de développement de WeChat Pay

Introduction détaillée au processus de développement de WeChat Pay

高洛峰
高洛峰original
2017-03-15 17:33:372037parcourir

Cet article présente principalement des informations pertinentes sur le processus de développement du paiement WeChat. Les amis qui en ont besoin peuvent s'y référer

Notez que j'utilise le paiement de la plateforme ouverte WeChat, qui est liée à l'application mobile. et non au public. Le récit n'est pas pertinent.

Le processus opérationnel principal du paiement WeChat

1. L'utilisateur parcourt l'application, sélectionne le produit et passe une commande.

2. Le serveur traite la logique de commande et démarre le processus de paiement formel

3 Tout d'abord, le serveur backend lance une requête au serveur weixin pour obtenir un jeton.

4. Le serveur backend récupère le jeton, le crypte avec d'autres paramètres et envoie à nouveau une requête au serveur weixin pour obtenir un identifiant de prépaiement

5 Le serveur backend renvoie l'identifiant de pré-paiement. le client de l'application

6. L'application appelle le contrôle WeChat sur le téléphone pour terminer le processus de paiement.

7.app lance une demande de rappel au serveur backend pour informer le serveur que la transaction est terminée.

8. Une fois que le serveur weixin a traité tous les processus, il initie une demande de publication au serveur backend pour informer officiellement le serveur backend que la transaction est terminée

Certains des processus ci-dessus Remarque :

1. Le jeton obtenu à chaque fois a une limite de temps, la valeur par défaut est de 7 200 secondes, et il peut être obtenu jusqu'à 200 fois par jour, il Il est préférable de le mettre dans redisCache et de le récupérer après son expiration

2 Le rappel initié par l'application n'est pas fiable par défaut. il est préférable (mais pas nécessairement) de lancer une commande requête auprès du serveur WeChat, vérifiez les résultats de cette transaction.

3. Le notify initié par le serveur weixin en arrière-plan est la dernière barrière pour garantir la finalisation de la transaction. Le serveur d'arrière-plan doit renvoyer « succès » après confirmation, sinon le serveur weixin tentera de renvoyer la demande.

Obtenir un jeton

Cette étape est très simple, il suffit d'envoyer une demande d'obtention. Configurez simplement les paramètres corrects.

‘‘‘从微信服务器获取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请求失败

Obtenir un prépayé

Dans le processus de développement de WeChat Pay, le plus fastidieux est d'obtenir prépayé.

Dans cette étape, nous devons assembler un tel paramètre :

{
"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&notify_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"
}

Assembler le package

La première étape ici consiste à assembler le colis :

"package":"bank_type=WX&body=%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%
95&fee_type=1&input_charset=UTF-8&notify_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",

Les paramètres requis pour assembler le colis sont tels qu'indiqués dans le code ci-dessus, nous devez préparer un paramètre, puis préparer la signature, le processus de signature est le suivant :

1 Triez les paramètres selon l'ordre du dictionnaire de la clé, puis divisez-les en chaîne. . Notez que ces clés n'incluent pas le signe

2 .Splice key=paternerKey après la chaîne ci-dessus, puis effectuez la signature md5 sur la chaîne entière, puis convertissez-la en majuscule. fois que nous obtenons la signature

et ensuite nous aurons tous les paramètres. La valeur est codée en urlen puis épissée avec sign=signValue pour obtenir la chaîne du package.

Le processus de création de MD5 ici est le suivant :

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

Le code pour assembler le package :

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

Continuer à assembler les paramètres

Après avoir reçu le colis, nous continuons à assembler les paramètres :

Les paramètres requis ici sont :

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&notify_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

traceid=test_1399514976

Notez qu'il y a une fosse ici :

Les paramètres ci-dessus sont impliqués dans la signature, mais le paramètre final n'inclut pas appKey. N'oubliez pas de supprimer après la signature.

1. Triez tous les paramètres par ordre lexicographique, puis collez-les

2 Signez la signature sha1 et collez-la à la fin de la chaîne ci-dessus

. 3. Faites attention à ce qui suit Supprimez l'appKey, puis ajoutez un signe

Le code pour obtenir la signature sha1 est le suivant :

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

Ensuite, nous obtenons des paramètres comme celui-ci :

{
"appid":"wxd930ea5d5a258f4f", 
"noncestr":"e7d161ac8d8a76529d39d9f5b4249ccb", 
"package":"Sign=WXpay";
"partnerid":"1900000109" 
"prepayid":"1101000000140429eb40476f8896f4c9", 
"sign":"7ffecb600d7157c5aa49810d2d8f28bc2811827b", 
"timestamp":"1399514976"
}

Obtenir un identifiant prépayé

Le code est le suivant :

‘‘‘获取预支付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

Le format prépayé que nous obtenons devrait être comme ceci :

{"prepayid":"1101000000140429eb40476f8896f4c9","errcode":0,"errmsg" :"Succès"}

Encore une signature

Ici, nous utilisons la méthode de signature sha1 ci-dessus pour signer à nouveau et obtenons les paramètres suivants :

{
"appid":"wxd930ea5d5a258f4f", 
"noncestr":"e7d161ac8d8a76529d39d9f5b4249ccb", 
"package":"Sign=WXpay";
"partnerid":"1900000109" 
"prepayid":"1101000000140429eb40476f8896f4c9", 
"sign":"7ffecb600d7157c5aa49810d2d8f28bc2811827b", 
"timestamp":"1399514976"
}

Le serveur d'arrière-plan Le résultat est renvoyé à l'application et l'application peut initier le paiement.

Le code de processus ci-dessus est :

‘‘‘接收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

Notification asynchrone en arrière-plan

Serveur WeChat La notification asynchrone notify envoyée est le signe final d'un paiement réussi. Cette étape est de sécurité Par souci de sécurité, nous devons prolonger la signature :

Le code d'extension est le suivant : <.>

def isTenpaySign(self, params):
    helper = WeixinRequestHandler()
    sign = helper.createMD5Signature(params)
    return params[‘sign‘] == sign

Le processus global est le suivant :

‘‘‘微信服务器向后台发送的异步通知‘‘‘
class WeixinAppNotifyHandler(BasicTemplateHandler):
  def initialize(self):
    self.weixinResponseHandler = WeixinResponseHandler()

  def post(self):
    ‘‘‘解析参数‘‘‘
    params = self.parseQueryString()

    ‘‘‘验证是否是weixin服务器发回的消息‘‘‘
    verifyWeixinSign = self.weixinResponseHandler.isTenpaySign(params)
    ‘‘‘处理订单‘‘‘
    if verifyWeixinSign:
      ‘‘‘订单逻辑‘‘‘
      order_no = str(params[‘out_trade_no‘])
      order_no = order_no[0:-2]
      print ‘%s paied successfully‘ % order_no
      self.saveWeixinReceipt(params)
      updateOrdersPaidByWeixin(order_no) #更新订单使用状态
      consumeCouponByOrderNo(order_no) #优惠券已经使用
      self.write("success")
    else:
      self.write("fail")

  def parseQueryString(self):
    ‘‘‘获取url中所有的参数‘‘‘
    uri = self.request.uri
    ‘‘‘解析出URI中的query字符串‘‘‘
    parseResult = urlparse.urlparse(uri) 
    query = parseResult.query
    ‘‘‘解析query字符串‘‘‘
    params = urlparse.parse_qs(query)
    for item in params:
      params[item] = params[item][0].strip()
    return params

Enfin, le paiement n'est pas considéré comme réussi lorsque l'utilisateur termine le paiement sur le téléphone mobile. Ce n'est que lorsque le serveur weixin reçoit le succès renvoyé par la notification que la transaction est finalement considérée comme réussie. peut recevoir le message officiel WeChat. Un message est arrivé.

Ce qui précède est la compilation d'informations sur le processus de développement des paiements WeChat. Nous continuerons à ajouter des informations pertinentes à l'avenir. Merci pour votre soutien à ce site !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn