小程序常用功能测试总结相关资料前言开发环境开发流程
发表时间:2023-10-03 16:17:31
文章来源:炫佑科技
浏览次数:156
菏泽炫佑科技 菏泽炫佑小程序开发 菏泽炫佑app制作 炫佑科技
小程序常用功能测试总结相关资料前言开发环境开发流程
微信小程序后端开发前言开发环境开发流程项目整体架构界面开发
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hi():
return "hi!"
if __name__ == "__main__":
app.run()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
http://
- 1
项目部署ip映射Nginx反向代理
# For more information on configuration, see:
# * Official English Documentation: /en/docs/
# * Official Russian Documentation: /ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main ''$remote_addr - $remote_user [$time_local] "$request" ''
''$status $body_bytes_sent "$http_referer" ''
''"$http_user_agent" "$http_x_forwarded_for"'';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See /en/docs/ngx_core_module.html#include
# for more information.
#include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
return 404;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
# Settings for a TLS enabled server.
#
# server {
# listen 443 ssl http2 default_server;
# listen [::]:443 ssl http2 default_server;
# server_name _;
# root /usr/share/nginx/html;
#
# ssl_certificate "/etc/pki/nginx/server.crt";
# ssl_certificate_key "/etc/pki/nginx/private/server.key";
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 10m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
#
# # Load configuration files for the default server block.
# include /etc/nginx/default.d/*.conf;
#
# location / {
# }
#
# error_page 404 /404.html;
# location = /40x.html {
# }
#
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# }
# }
# 自己主要要写的就下面这个server
server {
# 443是https监听的端口,一般默认就好
listen 443;
# 自己接口的主域名,这就是当我们访问时就会映射到这里
server_name ;
ssl on;
# 这是默认主页,接口没有主页就注释掉了
# root html;
# index index.html index.htm;
# 下面是阿里云下载的ssl证书,后面会说到ssl的配置,看不懂没关系
ssl_certificate ./xxx.pem;
ssl_certificate_key ./xxx.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
# 这里的意思是会和http://0.0.0.0:8888做一个映射,这就解决了上面*开始说的那个问题了,这一步很关键!
proxy_pass http://0.0.0.0:8888;
}
# 日志文件路径,有人访问你的网站时都会留下印记,有的话*好,不配置其实也行。
access_log /root/xxx/pjt/log/nginx.log;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
+超级多进程启动服务+进程监控ssl证书
由于小程序所需的接口都需要HTTPS连接,因此我们还需要SSL证书。 这里我使用的是阿里云服务器。 具体配置可以参考这里。 可能有点难以理解。 简单说一下我的配置。 :
我选择了单域名的免费DV SSL。 其实对于一般应用来说,单个域名就足够了。 从官网下载SSL证书微信小程序开发外卖,通常是两个文件:xxx.key和xxx.pem。 这是上面的 Nginx 反向代理配置所必需的。 可以返回上面的nginx.conf文件来查看! 管理证书,这是一个配置问题,官方文档很详细。 配置成功后小程序常用功能测试总结相关资料前言开发环境开发流程,您可以使用 或 访问您的网站,然后返回 hi!。 当然,也有可能无法访问。 通常是配置问题。 https其实就是访问http,只不过中间多了一个验证过程。 ,有兴趣的可以去这里了解一下http和https的区别。 附: 建议使用证书所在的服务器。 推荐腾讯云、阿里云。 其他人确实很难比拟。 我个人也遇到过很多陷阱! 小程序功能是微信支付。
有些小程序涉及微信支付,比如校园懒人。 这其实是一个很头疼的问题。 做了之后你就知道难不难了。 过程非常繁琐,官方文档也有很多坑。 下面我们简单解释一下:
首先,您必须注册公司。 *好让运营或者产品的同学来做这件事。 一般来说,支付是单向的,即用户向公司支付费用。 如果公司向用户付费,则需要9个月的时间才能申请。 只需要时间。 这有点棘手。 当然,您不需要等待退款。 具体细节可以先阅读文档。 非常清晰,包括一些界面说明。 这里我写了一个微信预付款 是一个比较通用的类。 您只需更改参数并使用它即可。 我在官方文档中一一尝试过,确实很混乱:
class WeiXinPay(object):
"""微信支付,返回回客户端需要参数
"""
def __init__(self, uu_id, open_id, spbill_create_ip, total_fee, out_trade_no):
"""
:param total_fee: 订单金额
:param spbill_create_ip: 客户端请求IP地址
"""
self.params = {
''appid'': ''小程序的appid'',
''attach'': u''你的应用名称,我这里是(校园懒人邦)'',
''body'': u''校园懒人邦-代取费'',
''mch_id'': ''商户id,你企业的id'',
''nonce_str'': ''给个随机数,一般md5一下就好,时间戳啊或者别的什么'',
''notify_url'': ''result(这个就是通知地址,会异步返回信息给你),你写一个接口接收就行'',
''openid'': open_id,
''out_trade_no'': out_trade_no,
''spbill_create_ip'': spbill_create_ip,
''total_fee'': str(total_fee),
''trade_type'': ''JSAPI''
}
# 官方给的接口
self.url = ''https://api.mch.weixin.qq.com/pay/unifiedorder''
self.error = None
def key_value_url(self, value):
"""将将键值对转为 key1=value1&key2=value2
"""
key_az = sorted(value.keys())
pair_array = []
for k in key_az:
v = value.get(k, '''').strip()
v = v.encode(''utf8'')
k = k.encode(''utf8'')
pair_array.append(''%s=%s'' % (k, v))
tmp = ''&''.join(pair_array)
return tmp
def get_sign(self, params):
"""生成sign
"""
stringA = self.key_value_url(params)
stringSignTemp = stringA + ''&key='' + ''xxx'' # APIKEY, API密钥,需要在商户后台设置
sign = (md5(stringSignTemp).hexdigest()).upper()
params[''sign''] = sign
def get_req_xml(self):
"""拼接XML
"""
self.get_sign(self.params)
xml = ""
for k, v in self.params.items():
v = v.encode(''utf8'')
k = k.encode(''utf8'')
xml += ''<'' + k + ''>'' + v + '''' + k + ''>''
xml += " "
print xml
return xml
def get_prepay_id(self):
"""
请求获取prepay_id
"""
xml = self.get_req_xml()
headers = {''Content-Type'': ''application/xml''}
r = requests.post(self.url, data=xml, headers=headers)
re_xml = ElementTree.fromstring(r.text.encode(''utf8''))
xml_status = re_xml.getiterator(''result_code'')[0].text
if xml_status != ''SUCCESS'':
self.error = u"连接微信出错啦!"
logging.error(u"连接微信出错啦!")
return
prepay_id = re_xml.getiterator(''prepay_id'')[0].text
self.params[''package''] = ''prepay_id=%s'' % prepay_id
self.params[''timestamp''] = str(int(time.time()))
def re_finall(self):
self.get_prepay_id()
if self.error:
return
sign_again_params = {
''appId'': self.params[''appid''],
''timeStamp'': self.params[''timestamp''],
''nonceStr'': self.params[''nonce_str''],
''package'': self.params[''package''],
''signType'': ''MD5''
}
self.get_sign(sign_again_params)
sign_again_params[''paySign''] = sign_again_params[''sign'']
sign_again_params[''total_fee''] = self.params[''total_fee'']
sign_again_params[''notify_url''] = self.params[''notify_url'']
sign_again_params.pop(''appId'')
sign_again_params.pop(''sign'')
return json.dumps(sign_again_params)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
5 这里返回的*后一个参数可以传给前台进行支付。 前台会给你取,然后你就可以按照指定的金额付款。
6 退款方面存在一些差异。 首先,先查看文档。 我还在下面写了一个更通用的类。 如果觉得文档麻烦,可以直接使用:
class WeiXinReturn(object):
def __init__(self, out_trade_no, total_fee, refund_fee):
self.params_mach = {
# 申请商户号的appid或商户号绑定的appid
''appid'': ''xxx'',
''mch_id'': ''xxx'',
''nonce_str'': ''随机数'',
''out_trade_no'': out_trade_no,
''out_refund_no'': ''微信订单号'',
''total_fee'': str(total_fee),
''refund_fee'': str(refund_fee),
''notify_url'': ''pay_return/result(和支付一样的意思,就是退款的通知地址,自己开发一个接口就好)''
}
def pay_return(self):
stringA = self.key_value_url(self.params_mach)
stringSignTemp = stringA + ''&key='' + ''xxx'' # APIKEY, API密钥,需要在商户后台设置
sign = (md5(stringSignTemp).hexdigest()).upper()
self.params_mach[''sign''] = sign
xml = ""
for k, v in self.params_mach.items():
v = v.encode(''utf8'')
k = k.encode(''utf8'')
xml += ''<'' + k + ''>'' + v + '''' + k + ''>''
xml += " "
headers = {''Content-Type'': ''application/xml;charset=UTF-8''}
# url = ''https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers''
url = ''https://api.mch.weixin.qq.com/secapi/pay/refund''
# 请求中需要带有支付的证书,没有证书是无法申请的
r = requests.post(url, data=xml, headers=headers, cert=(''xxx.pem'', ''xxx.pem''))
result = r.text
re_xml = ElementTree.fromstring(r.text.encode(''utf8''))
xml_status = re_xml.getiterator(''result_code'')[0].text
if xml_status == ''SUCCESS'':
return True
return False
def key_value_url(self, value):
"""将将键值对转为 key1=value1&key2=value2
"""
key_az = sorted(value.keys())
pair_array = []
for k in key_az:
v = value.get(k, '''').strip()
v = v.encode(''utf8'')
k = k.encode(''utf8'')
pair_array.append(''%s=%s'' % (k, v))
tmp = ''&''.join(pair_array)
return tmp
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
附: 这里需要提供商家证明。 详细信息请参见此处。
生成二维码
def upload_img(self, local_path, upload_name, bucket_name, ttl=7200):
"""
上传图片到七牛云
:param local_path: 本地文件路径
:param upload_name: 上传文件名
:param bucket_name: 七牛申请的存储空间名称
:param ttl: 过期时间
:return: 返回图片地址
"""
from qiniu import Auth, put_file
import re
q = Auth(access_key=conf_test.AccessKey, secret_key=conf_test.SecretKey)
token = q.upload_token(bucket_name, upload_name, ttl)
ret, info = put_file(token, upload_name, local_path)
pat_status = ''status_code:(.*?),''
status_code = re.compile(pat_status, re.S).findall(str(info))
if len(status_code) > 0:
# 成功返回图片外链名称,失败返回原因以及状态码
if int(status_code[0]) == 200:
return {"msg":conf_test.qiniu_domain + upload_name, "status":1}
return {"msg":"failed upload img failed", "status":-1}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
转发新闻
# 刷新用户form_id 存入redis
def fresh_formid(self, **kwargs):
"""
接收前台传来的form_id存入redis
:param kwargs:
:return:
"""
uu_id = kwargs.get("uu_id", "")
if not uu_id:
return "failed: uu_id cannot be null"
open_id = kwargs.get("open_id", "")
if not open_id:
return "failed: open_id cannot be null"
form_id = kwargs.get("form_id", "")
if not form_id:
return "failed: form_id cannot be null"
if "invalid code" in open_id:
return "failed: get openid err"
msg = {open_id: form_id}
self.redis_cli.sadd(uu_id, json.dumps(msg))
return "success"
# 发消息模板
def send_template_msg(self, **kwargs):
uu_id = kwargs.get("uu_id", "")
if not uu_id:
return "failed: uu_id cannot be null"
data = kwargs.get("data", "")
if not data:
return "failed: data can not be null"
# 这个token可以从文档中去查看怎么得到,内部源码不能提供
token = self.get_refresh_token()
if not token:
return "failed: cannot find a token"
send_msg = {}
# 从redis中取出用户对应的form_id
redis_msg = self.redis_cli.spop(uu_id)
if not redis_msg:
return "failed: cannot find a open_id in redis"
msg = json.loads(redis_msg.encode("utf8"))
touser = msg.keys()[0]
form_id = msg[touser]
template_id = kwargs.get("template_id", "")
if not template_id:
return "failed: template_id cannot be null"
# page是用户点开消息后跳转到的页面
page = kwargs.get("page", "")
# 下面这些参数的含义在文档中都能查到
emphasis_keyword = kwargs.get("emphasis_keyword", "")
send_msg["touser"] = touser
send_msg["template_id"] = template_id
send_msg["page"] = page
send_msg["form_id"] = form_id
send_msg["data"] = data
send_msg["emphasis_keyword"] = emphasis_keyword
# 调起发送消息接口
api = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=%s" % token
# post方式发起网络请求
return self.get_html(url=api, data=send_msg)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
测试黑盒测试qps测试
class PressTest(object):
def __init__(self):
pass
def get_html(self, url, headers=conf_test.HEADERS, data=None):
if data:
data = json.dumps(data)
req = urllib2.Request(url=url, headers=headers, data=data)
response = urllib2.urlopen(req)
html = response.read()
return html
def get_test(self, api_url):
result = self.get_html(url=api_url)
if not result:
print "url %s result is none" %api_url
return
return
def post_test(self, api_url, **kwargs):
import time
start_time = time.time()
result = self.get_html(url=api_url, data=kwargs)
print result
if not result:
print "url %s result is none" % api_url
end_time = time.time()
all = end_time - start_time
print all
if __name__ == ''__main__'':
press_test = PressTest()
print "requesting........."
api_url = ''https://xxx接口1''
api_url2 = ''https://xxx接口2''
start = time.time()
times = 400
for i in range(times):
t1 = threading.Thread(target=press_test.get_test, args=(api_url,))
t2 = threading.Thread(target=press_test.get_test, args=(api_url2,))
t1.start()
t2.start()
t1.join()
t2.join()
end = time.time()
ave = (end - start) / 800.0
print "count:%d, start_time :%s, now_time: %s, average_qps: %s" % (800, str(start), str(end), str(ave))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
总结