草庐IT

Python3 微信支付(小程序支付)V3接口

宗乐平 2023-09-22 原文

起因:

        因公司项目需要网上充值功能,从而对接微信支付,目前也只对接了微信支付的小程序支付功能,在网上找到的都是对接微信支付V2版本接口,与我所对接的接口版本不一致,无法使用,特此记录下微信支付完成功能,使用Django完成后端功能,此文章用于记录使用,

        以下代码仅供参考,如若直接商用出现任何后果请自行承担,本人概不负责。

功能:

       调起微信支付,微信回调

代码:
       
1、准备工作:

mchid = "xxxxxx"                         # 商户号
pay_key = "xxxxxx"                       # 商户秘钥V3 使用V3接口必须使用V3秘钥
serial_num = "xxxxxx"                    # 证书序列号

# ======================前三个参数在微信支付中可找到===============================
# ============ 商户号(mchid ) 在账户中心——商户信息——微信支付商户号 (是纯数字) ==================
# ============= 商户秘钥(pay_key) 在账户中心——API安全——APIv3秘钥 (需手动设置) ===================
# ============= 证书序列号(serial_num) 在账户中心——API安全——API证书 (需手动申请,通过后会有串证书序列号),申请完成后需要把证书下载到项目中,便于使用 ===================



appid = "xxxxxx"                         # 微信小程序appid 
wx_secret ="xxxxxx"                      # 微信小程序秘钥
# ============= 微信小程序appid 在产品中心——AppID账号管理——添加关联的AppID  ===================     

WX_Pay_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
# ============= 微信支付调用地址,用于请求接收 预支付交易会话标识: prepay_id =================== 


WX_Notify_URL = "https://127.0.0.1:8000"  
# ============= 接收微信支付回调地址,必须是https ===================         

        2、调起微信支付(后端只能请求微信支付接口向微信支付官方获取到预支付交易会话标识,并返回给前端,前端才能调起输入密码支付界面)

import json
import decimal
import traceback

import requests
from django.http import HttpResponse


def payment_view(request, *args, **kwargs):
    """
    微信支付(小程序)
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    try:
        reqdata = json.loads(request.body)
        # 前端参数
        jscode = reqdata["jscode"]  # 微信ID
        price = decimal.Decimal(reqdata["price"]).quantize(decimal.Decimal("0.00"))  # 充值金额,保留两位小数
        nickname = reqdata["nickname"]  # 微信昵称/支付宝名称 前端获取到返给后端做记录,可要可不要的字段
        paymode = reqdata["paymode"]  # 支付方式  1微信支付
        remark = reqdata["remark"]  # 支付内容描述
        
        # 根据jscode 获取openID
        rets = requests.get(url = "https://api.weixin.qq.com/sns/jscode2session?" \
              "appid=%s&secret=%s&js_code=%s" \
              "&grant_type=authorization_code" % (appid,wx_secret, js_code), timeout=3, verify=False)
        if not rets:
            return HttpResponse(general_error_msg(msg="未获取到微信信息"))

        # 0.获取支付的微信openid
        print(f"组织ID:{userinfo['orgid']}, jscode:{jscode}")
        wxuser = getappopenid(orgid, jscode)
        if wxuser:
            # session_key = wxuser["session_key"]
            openid = wxuser["openid"]
        else:
            return HttpResponse(general_error_msg(msg="未获取到微信用户信息"))

        # 1.以交易日期生成交易号
        orderno = order_num()
        # 2.生成新交易记录 paystatus 支付状态  1成功 0待支付 -1支付失败
        conorder.objects.create(orderno=orderno, openid=openid, openname=nickname,
                                paymode=paymode,goodstotalprice=price, paystatus=0, 
                                remark=remark,createtime=get_now_time(1))
        # 3.生成统一下单的报文body
        url = WX_Pay_URL
        body = {
            "appid": appid,
            "mchid": mchid,
            "description": remark,
            "out_trade_no": orderno,
            "notify_url": WX_Notify_URL + "/pay/notify",  # 后端接收回调通知的接口
            "amount": {"total": int(price * 100), "currency": "CNY"},  # 正式上线price要*100,微信金额单位为分(必须整型)。
            "payer": {"openid": openid},
        }
        data = json.dumps(body)

        headers, random_str, time_stamps = make_headers_v3(mchid, serial_num, data=data, method='POST')

        # 10.发送请求获得prepay_id
        try:
            response = requests.post(url, data=data, headers=headers)  # 获取预支付交易会话标识(prepay_id)
            print("预支付交易会话标识", response)
            if response.status_code == 200:
                wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate, serial_no = check_wx_cert(
                    response, mchid, pay_key, serial_num)
                # 11.9签名验证
                if wechatpay_serial == serial_no:  # 应答签名中的序列号同证书序列号应相同
                    print('serial_no match')
                    try:
                        data3 = f"{wechatpay_timestamp}\n{wechatpay_nonce}\n{response.text}\n"
                        verify(data3, wechatpay_signature, certificate)
                        print('The signature is valid.')
                        # 12.生成调起支付API需要的参数并返回前端
                        res = {
                            'orderno': orderno,  # 订单号
                            'timeStamp': time_stamps,
                            'nonceStr': random_str,
                            'package': 'prepay_id=' + response.json()['prepay_id'],
                            'signType': "RSA",
                            'paySign': get_sign(f"{appid}\n{time_stamps}\n{random_str}\n{'prepay_id=' + response.json()['prepay_id']}\n"),
                        }
                        return HttpResponse(success_msg(msg="下单成功", total=0, data=res))
                    except Exception as e:
                        log.error(f"证书序列号验签失败{e}, {traceback.format_exc()}")
                        return HttpResponse(general_error_msg(msg="下单失败"))
                else:
                    log.error(f"证书序列号比对失败【请求头中证书序列号:{wechatpay_serial};本地存储证书序列号:{serial_no};】")
                    return HttpResponse(general_error_msg(msg="调起微信支付失败!"))
            else:
                log.error(f"获取预支付交易会话标识 接口报错【params:{data};headers:{headers};response:{response.text}】")
                return HttpResponse(general_error_msg(msg="调起微信支付失败!"))
        except Exception as e:
            log.error(f"调用微信支付接口超时【params:{data};headers:{headers};】:{e},{traceback.format_exc()}")
            return HttpResponse(general_error_msg(msg="微信支付超时!"))
    except Exception as e:
        log.error(f"微信支付接口报错:{e},{traceback.format_exc()}")
        return HttpResponse(general_error_msg(msg="微信支付接口报错!"))

3、相关方法

import base64
import random
import string
import time
import traceback
from datetime import datetime

import requests
from BaseMethods.log import log
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Cryptodome.Hash import SHA256
from sqlalchemy.util import b64encode
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

# 各包版本
# django-ratelimit==3.0.1
# SQLAlchemy~=1.4.44
# pycryptodome==3.16.0
# pycryptodomex==3.16.0
# cryptography~=38.0.4
# Django~=3.2.4

# 获取唯一标识
def get_uuid(utype=0):
    """
    唯一码
    :param utype:
    :return:
    """
    if utype == 0:
        return uuid.uuid1()
    elif utype == 1:
        return str(uuid.uuid1())
    elif utype == 2:
        return str(uuid.uuid1().hex)
    elif utype == 3:
        return str((uuid.uuid5(uuid.NAMESPACE_DNS, str(uuid.uuid1()) + str(random.random()))))


# 获取当前时间
def get_now_time(type=0):
    """
    :param type: 类型0-5
    :return: yyyy-mm-dd HH:MM:SS;y-m-d H:M:S.f;y-m-d;ymdHMS;y年m月d日h时M分S秒
    """
    if type == 0:
        return datetime.datetime.now()
    elif type == 1:
        return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    elif type == 2:
        return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
    elif type == 3:
        return datetime.datetime.now().strftime("%Y-%m-%d")
    elif type == 4:
        return datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    elif type == 5:
        locale.setlocale(locale.LC_CTYPE, 'chinese')
        timestr = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        t = time.strptime(timestr, "%Y-%m-%d %H:%M:%S")
        result = (time.strftime("%Y年%m月%d日%H时%M分%S秒", t))
        return result
    elif type == 6:
        return datetime.datetime.now().strftime("%Y%m%d")


# 重构系统jargon类,用于处理时间格式报错问题
class DateEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(obj, datetime.date):
            return obj.strftime("%Y-%m-%d")
        elif isinstance(obj, Decimal):
            return float(obj)
        elif isinstance(obj, bytes):
            return str(obj, encoding='utf-8')
        elif isinstance(obj, uuid.UUID):
            return str(obj)
        elif isinstance(obj, datetime.time):
            return obj.strftime('%H:%M')
        elif isinstance(obj, datetime.timedelta):
            return str(obj)
        else:
            return json.JSONEncoder.default(self, obj)




def decrypt(nonce, ciphertext, associated_data, pay_key):
    """
    AES解密
    :param nonce:
    :param ciphertext:
    :param associated_data:
    :param pay_key:
    :return:
    """
    key = pay_key
    key_bytes = str.encode(key)
    nonce_bytes = str.encode(nonce)
    ad_bytes = str.encode(associated_data)
    data = base64.b64decode(ciphertext)
    aesgcm = AESGCM(key_bytes)
    return aesgcm.decrypt(nonce_bytes, data, ad_bytes)


def order_num():
    """
    生成订单号
    :return:
    """
    # 下单时间的年月日毫秒12+随机数8位
    now_time = datetime.now()
    result = str(now_time.year) + str(now_time.month) + str(now_time.day) + str(now_time.microsecond) + str(
        random.randrange(10000000, 99999999))
    return result


def get_sign(sign_str):
    """
    定义生成签名的函数
    :param sign_str:
    :return:
    """
    try:
        with open(r'static/cret/apiclient_key.pem') as f:
            private_key = f.read()
        rsa_key = RSA.importKey(private_key)
        signer = pkcs1_15.new(rsa_key)
        digest = SHA256.new(sign_str.encode('utf-8'))
        # sign = b64encode(signer.sign(digest)).decode('utf-8')
        sign = b64encode(signer.sign(digest))
        return sign
    except Exception as e:
        log.error("生成签名的函数方法报错【func:get_sign;sign_str:%s】:%s ==> %s" % (sign_str, e, traceback.format_exc()))


def check_wx_cert(response, mchid, pay_key, serial_no):
    """
    微信平台证书
    :param response: 请求微信支付平台所对应的的接口返回的响应值
    :param mchid: 商户号
    :param pay_key: 商户号秘钥
    :param serial_no: 证书序列号
    :return:
    """
    wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate = None, None, None, None, None
    try:
        # 11.应答签名验证
        wechatpay_serial = response.headers['Wechatpay-Serial']  # 获取HTTP头部中包括回调报文的证书序列号
        wechatpay_signature = response.headers['Wechatpay-Signature']  # 获取HTTP头部中包括回调报文的签名
        wechatpay_timestamp = response.headers['Wechatpay-Timestamp']  # 获取HTTP头部中包括回调报文的时间戳
        wechatpay_nonce = response.headers['Wechatpay-Nonce']  # 获取HTTP头部中包括回调报文的随机串
        # 11.1.获取微信平台证书 (等于又把前面的跑一遍,实际上应是获得一次证书就存起来,不用每次都重新获取一次)
        url2 = "https://api.mch.weixin.qq.com/v3/certificates"
        # 11.2.生成证书请求随机串
        random_str2 = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
        # 11.3.生成证书请求时间戳
        time_stamps2 = str(int(time.time()))
        # 11.4.生成请求证书的签名串
        data2 = ""
        sign_str2 = f"GET\n{'/v3/certificates'}\n{time_stamps2}\n{random_str2}\n{data2}\n"
        # 11.5.生成签名
        sign2 = get_sign(sign_str2)
        # 11.6.生成HTTP请求头
        headers2 = {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": 'WECHATPAY2-SHA256-RSA2048 '
                             + f'mchid="{mchid}",nonce_str="{random_str2}",signature="{sign2}",timestamp="{time_stamps2}",serial_no="{serial_no}"'
        }
        # 11.7.发送请求获得证书
        response2 = requests.get(url2, headers=headers2)  # 只需要请求头
        cert = response2.json()

        # 11.8.证书解密
        nonce = cert["data"][0]['encrypt_certificate']['nonce']
        ciphertext = cert["data"][0]['encrypt_certificate']['ciphertext']
        associated_data = cert["data"][0]['encrypt_certificate']['associated_data']
        serial_no = cert["data"][0]['serial_no']
        certificate = decrypt(nonce, ciphertext, associated_data, pay_key)
    except Exception as e:
        log.error(f"微信平台证书验证报错:{e};{traceback.format_exc()}")
    return wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate, serial_no


def verify(check_data, signature, certificate):
    """
    验签函数
    :param check_data:
    :param signature:
    :param certificate:
    :return:
    """
    key = RSA.importKey(certificate)  # 这里直接用了解密后的证书,但没有去导出公钥,似乎也是可以的。怎么导公钥还没搞懂。
    verifier = pkcs1_15.new(key)
    hash_obj = SHA256.new(check_data.encode('utf8'))
    return verifier.verify(hash_obj, base64.b64decode(signature))


def make_headers_v3(mchid, serial_num, data='', method='GET'):
    """
    定义微信支付请求接口中请求头认证
    :param mchid: 商户ID
    :param serial_num: 证书序列号
    :param data: 请求体内容
    :param method: 请求方法
    :return: headers(请求头)
    """
    # 4.定义生成签名的函数 get_sign(sign_str)
    # 5.生成请求随机串
    random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
    # 6.生成请求时间戳
    time_stamps = str(int(time.time()))
    # 7.生成签名串
    sign_str = f"{method}\n{'/v3/pay/transactions/jsapi'}\n{time_stamps}\n{random_str}\n{data}\n"
    # 8.生成签名
    sign = get_sign(sign_str)
    # 9.生成HTTP请求头
    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'WECHATPAY2-SHA256-RSA2048 '
                         + f'mchid="{mchid}",nonce_str="{random_str}",signature="{sign}",timestamp="{time_stamps}",serial_no="{serial_num}"'
    }
    return headers, random_str, time_stamps

4、微信回调

import decimal
import json
import traceback

from django.http import HttpResponse


def notify_view(request, *args, **kwargs):
    """
    支付完成之后的通知(微信官方返回的数据)
    :param request:
    :param args:
    :param kwargs:
    :return:
    """
    try:
        # 1.获得支付通知的参数
        body = request.body
        data = bytes.decode(body, 'utf-8')
        newdata = json.loads(data)
        # newdata = {
        #     "id": "9d40acfd-13cb-5175-a5aa-6c421f794952",
        #     "create_time": "2023-01-06T15:12:49+08:00",
        #     "resource_type": "encrypt-resource",
        #     "event_type": "TRANSACTION.SUCCESS",
        #     "summary": "\xe6\x94\xaf\xe4\xbb\x98\xe6\x88\x90\xe5\x8a\x9f",
        #     "resource": {
        #         "original_type":
        #         "transaction",
        #         "algorithm": "AEAD_AES_256_GCM",
        #         "ciphertext": "UF5gLXfe8qBv9qxQsf+/Mb6as+vbIhUS8Dm25qGIJIIdXTorUUjqZH1+"
        #                       "jMQxkxma/Gn9bOxeAoQWPEuIoJ2pB328Iv90jmHTrouoP3L60mjNgGJS8d3H8i1zAPBXCpP4mgvgRANWsw4pAWj1lFM5BZr4aP+"
        #                       "pNMc5TdwreGBG3rO9sbCLXsSRfW8pVZ7IfPnhPDTOWP3P1k5ikHedcRt4/HP69oDBEe5RSsD93wO/"
        #                       "lrIwycStVHyecBaliwpVMRnNnRCXqhlalNJ3NJ6jcgy32fP1J+L90ntwGyqMmZUS71P5TN1H0iH5rXNpRY9IF3pvN+"
        #                       "lei5IS86wEoVXkmEsPcJrHaabn7rghxuZoqwuauMIiMwBLllnEmgXfAbJA4FJy+"
        #                       "OLhZPrMWMkkiNCLcL069QlvhLXYi/0V9PQVTnvtA5RLarj26s4WSqTZ2I5VGHbTqSIZvZYK3F275KEbQsemYETl18xwZ+"
        #                       "WAuSrYaSKN/pKykK37vUGtT3FeIoJup2c6M8Ghull3OcVmqCOsgvU7/pNjl1rLKEJB6t/X9avcHv+feikwQBtBmd/b2qCeSrEpM7US",
        #         "associated_data": "transaction",
        #         "nonce": "cKEdw8eV9Bh0"
        #     }
        # }
        nonce = newdata['resource']['nonce']
        ciphertext = newdata['resource']['ciphertext']
        associated_data = newdata['resource']['associated_data']

        try:
           payment = decrypt(nonce, ciphertext, associated_data, pay_key)
           break
        except Exception as e:
           print(e)
        if not payment:
            return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
        payment = eval(payment.decode('utf-8'))
        # payment = {
        #     "mchid": "xxxx",
        #     "appid": "xxxx",
        #     "out_trade_no": "20231654836163523608",
        #     "transaction_id": "4200001646202301065425000524",
        #     "trade_type": "JSAPI",
        #     "trade_state": "SUCCESS",
        #     "trade_state_desc": "\xe6\x94\xaf\xe4\xbb\x98\xe6\x88\x90\xe5\x8a\x9f",
        #     "bank_type": "OTHERS",
        #     "attach": "",
        #     "success_time": "2023-01-06T15:12:49+08:00",
        #     "payer": {
        #         "openid": "xxxxx"
        #     },
        #     "amount": {
        #         "total": 1,
        #         "payer_total": 1,
        #         "currency": "CNY",
        #         "payer_currency": "CNY"
        #     }
        # }
        orderno = payment['out_trade_no']
        zf_status = True if payment["trade_state"] == "SUCCESS" else False
        if zf_status:
            money = decimal.Decimal(int(payment["amount"]["payer_total"]) / 100).quantize(decimal.Decimal("0.00"))
        else:
            money = decimal.Decimal(0.0).quantize(decimal.Decimal("0.00"))
        # 7.回调报文签名验证
        # 同第一篇签名验证的代码
        wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate, serial_no = check_wx_cert(request, mchid, pay_key, serial_num)
        if wechatpay_serial == serial_no:  # 应答签名中的序列号同证书序列号应相同
            # 8.获得回调报文中交易号后修改已支付订单状态
            res = conorder.objects.filter(orderno=orderno, paystatus=0).first()
            if res:
                res.paystatus = 1
                res.save()
            else:
                res.paystatus = -1
                res.save()
            # 9.项目业务逻辑
            return HttpResponse({"code": "SUCCESS", "message": "成功"})
        else:
            log.error(f"证书序列号比对失败【请求头中证书序列号:{wechatpay_serial};本地存储证书序列号:{serial_num};】")
            return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
    except Exception as e:
        log.error(f"微信回调接口报错:{e},{traceback.format_exc()}")
        return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)

5、对应表模型

        

class conorder(models.Model):
    id = models.CharField(db_column='id', max_length=50, default=getuuid, primary_key=True, verbose_name="订单ID")
    orderno = models.CharField(db_column='orderno', max_length=50, null=False, blank=False, verbose_name="订单编号")
    serialno = models.CharField(db_column='serialno', max_length=50, null=True, blank=False, verbose_name="流水号")
    openid = models.CharField(db_column='openid', max_length=50, null=True, blank=False, verbose_name="微信ID/支付宝ID")
    openname = models.CharField(db_column='openname', max_length=255, null=True, blank=False,
                                verbose_name="微信名称/支付宝名称")
    orgid = models.CharField(db_column='orgid', max_length=50, null=False, blank=False, verbose_name="组织机构ID")
    iotuserid = models.CharField(db_column='iotuserid', max_length=50, null=False, blank=False, verbose_name="人员ID")
    invoice = models.CharField(db_column='invoice', max_length=50, null=True, blank=False, verbose_name="发票")
    invoicenum = models.CharField(db_column='invoicenum', max_length=50, null=True, blank=False, verbose_name="发票号码")
    paymode = models.SmallIntegerField(db_column='paymode', null=False, blank=False, verbose_name="支付模式 1微信支付")
    paysource = models.CharField(db_column='paysource', max_length=50, null=True, blank=False,
                                 verbose_name="支付来源 如零钱/银行卡")
    goodstotalprice = models.DecimalField(db_column='goodstotalprice', max_digits=12, decimal_places=2, null=False, blank=False,
                                          verbose_name="充值金额 单位元")
    paystatus = models.SmallIntegerField(db_column='paystatus', null=False, blank=False,
                                         verbose_name="支付状态  1成功 0待支付 -1支付失败")
    remark = models.CharField(db_column='remark', max_length=200, null=True, blank=False, verbose_name="备注")
    delstate = models.SmallIntegerField(db_column='delstate', default=0, verbose_name='数据状态 0正常 1已删除')
    createtime = models.DateTimeField(db_column='createtime', auto_now_add=True, null=True, verbose_name="建立时间")
    createoprid = models.CharField(db_column='createoprid', max_length=50, null=True, verbose_name="建立人员")
    updatetime = models.DateTimeField(db_column='updatetime', auto_now=True, null=True, verbose_name="更新时间 充值成功与否的时间")
    updateoprid = models.CharField(db_column='updateoprid', max_length=50, null=True, verbose_name="更新人员")

    class Meta:
        db_table = "order"
        indexes = [
            models.Index(fields=['iotuserid'], name='order_userid'),
        ]
        verbose_name = "充值订单表"
        verbose_name_plural = verbose_name

6、借鉴地址:

        在此非常感谢博主,文章链接如下:一文基本搞定python的django框架下微信支付v3的主要流程-1 - 知乎​​​​​​从去年底开始,下决心自己写代码来搞定自已策划的微信小程序” 来推鉴--投融资项目推荐服务平台“后,微信支付就成为挡在前面的一座大山。毕竟是从一个从没开发过一个程序的基本零基础,到要真正上线一个能商业运…https://zhuanlan.zhihu.com/p/402449405

7、请注意:

        以上代码仅供参考,如若直接商用出现任何后果请自行承担,本人概不负责。 

有关Python3 微信支付(小程序支付)V3接口的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  4. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  5. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  6. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  7. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  8. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  9. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  10. ruby - 检查是否通过 require 执行或导入了 Ruby 程序 - 2

    如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby​​文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否

随机推荐