龙空技术网

学习猿地 python教程 django教程5 华为云+阿里云支付

学习猿地知识社区 115

前言:

此刻姐妹们对“ecsnginxuwsgi”大约比较关怀,我们都需要剖析一些“ecsnginxuwsgi”的相关文章。那么小编也在网上收集了一些对于“ecsnginxuwsgi””的相关文章,希望大家能喜欢,同学们快快来了解一下吧!

# 华为云服务器+Nginx+Python3.7+Django2.2+支付宝支付接入部署

> 本次分享内容共分四个主要部署步骤

> 1.Django框架项目搭建部署

> 2.本地内网穿透测试

> 3.阿里支付宝支付接口部署

> 4.华为云服务器部署(弹性云服务器ECS)

## 一,搭建django项目基本结构

### 1.创建当前项目的虚拟环境

` python3 -m venv venv `

### 2.安装依赖环境

> ` pip install -r requirement.txt`

```

Django==2.2.6

Pillow==6.2.0

pkg-resources==0.0.0

pycrypto==2.6.1

pycryptodomex==3.7.2

python-alipay-sdk==1.10.1

pytz==2019.3

sqlparse==0.3.0

```

### 3.完成项目基本结构开发(略...)

> 按照基本模型和路由参考,完成以下基本项目功能:

> 1.商品列表页:需要完成数据的查询及模板中的数据展示

> 2.商品下单: 在商品列表页可以对商品进行下单购买,及对应的订单数据入库操作

> 3.订单列表: 可以查看到当前所有订单及订单的支付状态

> 4.完成发起支付请求,支付回调地址的视图函数定义(代码可以暂时不写)

模型 models.py

```python

from django.db import models

from django.utils.html import format_html

# Create your models here.

# 书籍模型

class Books(models.Model):

# 书名

name = models.CharField(max_length=30)

# 价格

price = models.FloatField()

# 数量

num = models.IntegerField(default=5)

# 封面

img_url = models.ImageField(upload_to="./static/uploads/",null=True)

def loadimg(self):

return format_html('<img src="%s" height="64" width="64" />' %(self.img_url,))

class Order(models.Model):

# 订单号

ordercode = models.IntegerField()

# 下单用户id

user = models.CharField(max_length=5,default='测试用户')

# 购买产品id

bookid = models.IntegerField()

# 产品名称

bookname = models.CharField(max_length=50)

# 应付金额

monery = models.FloatField()

# 支付方式 0 支付宝

paytype = models.IntegerField(default=0)

# 支付状态 0未支付 1 已支付

paystatus = models.IntegerField(default=0)

# 订单创建时间

ordertime = models.DateTimeField(auto_now_add=True)

# 订单支付时间

paytime = models.DateTimeField(null=True)

```

路由及对应视图函数 urls.py

```python

# 商品列表

path('',views.index),

# 创建订单

path('order/create', views.create_order,name="createOrder"),

# 发起支付请求

path('order/pay', views.order_pay_request,name="orderpay"),

# 支付宝回调地址

path('order/pay_result', views.order_pay_result,name="order_pay_result"),

# 订单列表,支付成功后的跳转页面

path('order/list', views.orderlist,name="orderlist"),

# 订单删除

path('order/delete', views.orderdel,name="orderdel"),

```

## 二,使用ngrok|花生壳内网穿透

> 推荐使用花生壳进行内网穿透测试

>

## 三,支付宝接入

#### 1.登陆支付宝开放平台创建支付宝沙箱环境

> 支付宝开放平台

> 支付文档

#### 2.创建密钥

> 1.生成应用公钥和秘钥

> 2.把应用公钥赋值并配置到当前的沙箱环境中

> 3.配置完公钥后,沙箱环境配置会给一个支付宝公钥,复制并保存

> 4.在项目根目录中创建keys文件目录,存储应用私钥(rsa_private_key.txt)和支付宝公钥(rsa_public_key.txt)

ubuntu生成密钥和公钥

```shell

#打开终端输入 openssl

# 输入以下命令创建密钥

genrsa -out rsa_private_key.txt 2048

# 输入以下命令创建公钥

rsa -in rsa_private_key.txt -pubout -out rsa_public_key.txt

#输入 exit 推出 openssl

# ls 查看当前目录下创建的密钥和公钥

rsa_private_key.txt rsa_public_key.txt

```

windows10 可以安装支付宝开放平台助手,创建密钥

>

注意:在项目中配置 keys应用 私钥和支付宝公钥 放进来

```python

1,在项目中 创建 keys 目录 里面放入 秘钥文件

2,创建 rsa_private_key.txt 放入秘钥,加开始和结束的标记

-----BEGIN RSA PRIVATE KEY-----

.....

-----END RSA PRIVATE KEY-----

3,创建 rsa_public_key.txt 放入秘钥,加开始和结束的标记

-----BEGIN PUBLIC KEY-----

....

-----END PUBLIC KEY-----

```

#### 3. 项目中支付宝接口的配置 settings.py

1.参考以下配置在项目中进行支付宝相关配置

```python

# 支付宝相关配置

# APPID

# 沙箱APPID,生产环境须更改为应用APPID。

ALIPAY_APPID = "0000000000011111100"

# 网关

# 沙箱网关,生产环境须更改为正式网关。

ALIPAY_URL = ";

# 正式网关,开发环境勿使用。

# ALIPAY_URL = ";

# 回调通知地址

ALIPAY_NOTIFY_URL = ";

# 支付后的跳转地址

ALIPAY_RETURN_URL = ';

# 应用私钥

APP_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'keys/rsa_private_key.txt')

# 支付宝公钥

ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR, 'keys/rsa_public_key.txt')

```

#### 4.发起支付请求

1. 完成支付请求前基本开发

```python

# 首页

def index(request):

data = Books.objects.all()

return render(request,'index.html',{'data':data})

# 创建订单,发起支付请求

def create_order(request):

# 接受表单数据

id = request.POST.get('id')

# 获取对象

obj = Books.objects.get(id=id)

# 检测库存

if obj.num <= 0:

return JsonResponse({'code':1,'msg':'当前商品已经售空'})

# 创建订单

# 订单号,购买产品id,应付金额

data = {

'ordercode':int(time.time())+random.randint(10000,99999),

'bookid':obj.id,

'bookname':obj.name,

'monery':obj.price

}

orderobj = Order(**data)

orderobj.save()

print(f'订单创建成功,\r\n订单信息:{data}')

# return HttpResponse('创建订单,发起支付请求')

return order_pay_request(orderobj)

# 支付成功后的跳转页面

def orderlist(request):

# 获取所有的订单数据

data = Order.objects.all()

for i in data:

i.img = Books.objects.get(id=i.bookid).img_url

return render(request,'orderlist.html',{'data':data})

# 订单删除

def orderdel(request):

oid = request.GET.get('oid')

obj = Order.objects.get(id=oid)

obj.delete()

return HttpResponseRedirect(reverse('orderlist'))

```

2. 导入支付宝支付接口类

> 在项目根目录创建utils包文件夹,创建pay.py模块写入支付接口类

> web\utils\pay.py

```python

from datetime import datetime

from Crypto.PublicKey import RSA

from Crypto.Signature import PKCS1_v1_5

from Crypto.Hash import SHA256

from urllib.parse import quote_plus

from urllib.parse import urlparse, parse_qs

from base64 import decodebytes, encodebytes

import json

class AliPay(object):

"""

支付宝支付接口(PC端支付接口)

"""

def __init__(self, appid, app_notify_url, app_private_key_path,

alipay_public_key_path, return_url, debug=False):

self.appid = appid

self.app_notify_url = app_notify_url

self.app_private_key_path = app_private_key_path

self.app_private_key = None

self.return_url = return_url

with open(self.app_private_key_path) as fp:

self.app_private_key = RSA.importKey(fp.read())

self.alipay_public_key_path = alipay_public_key_path

with open(self.alipay_public_key_path) as fp:

self.alipay_public_key = RSA.importKey(fp.read())

if debug is True:

self.__gateway = ";

else:

self.__gateway = ";

def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):

biz_content = {

"subject": subject,

"out_trade_no": out_trade_no,

"total_amount": total_amount,

"product_code": "FAST_INSTANT_TRADE_PAY",

# "qr_pay_mode":4

}

biz_content.update(kwargs)

data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)

return self.sign_data(data)

def build_body(self, method, biz_content, return_url=None):

data = {

"app_id": self.appid,

"method": method,

"charset": "utf-8",

"sign_type": "RSA2",

"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),

"version": "1.0",

"biz_content": biz_content

}

if return_url is not None:

data["notify_url"] = self.app_notify_url

data["return_url"] = self.return_url

return data

def sign_data(self, data):

data.pop("sign", None)

# 排序后的字符串

unsigned_items = self.ordered_data(data)

unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)

sign = self.sign(unsigned_string.encode("utf-8"))

# ordered_items = self.ordered_data(data)

quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

# 获得最终的订单信息字符串

signed_string = quoted_string + "&sign=" + quote_plus(sign)

return signed_string

def ordered_data(self, data):

complex_keys = []

for key, value in data.items():

if isinstance(value, dict):

complex_keys.append(key)

# 将字典类型的数据dump出来

for key in complex_keys:

data[key] = json.dumps(data[key], separators=(',', ':'))

return sorted([(k, v) for k, v in data.items()])

def sign(self, unsigned_string):

# 开始计算签名

key = self.app_private_key

signer = PKCS1_v1_5.new(key)

signature = signer.sign(SHA256.new(unsigned_string))

# base64 编码,转换为unicode表示并移除回车

sign = encodebytes(signature).decode("utf8").replace("\n", "")

return sign

def _verify(self, raw_content, signature):

# 开始计算签名

key = self.alipay_public_key

signer = PKCS1_v1_5.new(key)

digest = SHA256.new()

digest.update(raw_content.encode("utf8"))

if signer.verify(digest, decodebytes(signature.encode("utf8"))):

return True

return False

def verify(self, data, signature):

if "sign_type" in data:

sign_type = data.pop("sign_type")

# 排序后的字符串

unsigned_items = self.ordered_data(data)

message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)

return self._verify(message, signature)

```

3. 支付请求及回调函数封装

```python

# 发起支付请求

def order_pay_request(orderobj):

# 获取支付对象

alipay = Get_AliPay_Object()

# 生成支付的url

query_params = alipay.direct_pay(

subject=orderobj.bookname, # 商品简单描述

out_trade_no = orderobj.ordercode,# 用户购买的商品订单号

total_amount = orderobj.monery, # 交易金额(单位: 元 保留俩位小数)

)

# 支付宝网关地址(沙箱应用)

pay_url = settings.ALIPAY_URL+"?{0}".format(query_params)

print('正在发起支付请求...')

# 页面重定向到支付页面

return HttpResponseRedirect(pay_url)

# 支付宝回调地址

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt

def order_pay_result(request):

# 获取对象

alipay = Get_AliPay_Object()

if request.method == "POST":

# 检测是否支付成功

# 去请求体中获取所有返回的数据:状态/订单号

from urllib.parse import parse_qs

# name&age=123....

body_str = request.body.decode('utf-8')

post_data = parse_qs(body_str)

post_dict = {}

for k, v in post_data.items():

post_dict[k] = v[0]

sign = post_dict.pop('sign', None)

status = alipay.verify(post_dict, sign)

print('------------------开始------------------')

print('POST验证', status)

print(post_dict)

out_trade_no = post_dict['out_trade_no']

# 修改订单状态

ass = {'paystatus':1,'paytime':post_dict['gmt_payment']}

print(ass)

Order.objects.filter(ordercode=out_trade_no).update(**ass)

print('------------------结束------------------')

# 修改订单状态:获取订单号

return HttpResponse('success')

else:

params = request.GET.dict()

sign = params.pop('sign', None)

status = alipay.verify(params, sign)

print('==================开始==================')

print('GET验证', status)

print('==================结束==================')

return HttpResponse('<script>alert("支付成功");location.href="/order/list"</script>')

# 支付宝对象创建方法

from web import settings

from utils.pay import AliPay

# AliPay 对象实例化

def Get_AliPay_Object():

alipay = AliPay(

appid=settings.ALIPAY_APPID,# APPID (沙箱应用)

app_notify_url=settings.ALIPAY_NOTIFY_URL, # 回调通知地址

return_url=settings.ALIPAY_RETURN_URL,# 支付完成后的跳转地址

app_private_key_path=settings.APP_PRIVATE_KEY_PATH, # 应用私钥

alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH, # 支付宝公钥

debug=True, # 默认False,

)

return alipay

```

## 四.上线华为云服务器部署(弹性云服务器ECS)

环境配置:

ubuntu 18.04

Python 3.6.8(python3.7亦可)

nginx version: nginx/1.14.0 (Ubuntu)

#### 1. 购买华为云服务器

> 文档

#### 2. 上传到华为云服务器,安装依赖环境,启动项目测试

#### 3. 搭建uwsgi启动项目测试

1.安装uwsgi

sudo pip3 install uwsgi --upgrade

2.安装完成后使用命令测试

先进入项目目录,启动命令

uwsgi --http :80 --chdir /home/alipay/web --module web.wsgi --home /home/alipay/venv/bin

# --home 指定virtualenv 路径,如果没有可以去掉。web.wsgi 指的是 web/wsgi.py 文件

3.访问测试,启动成功后

127.0.0.1:8080

#### 4. 配置uwsgi文件启动项目

第一步:创建一个uwsgi.ini文件

第二步:在django项目同级目录创建script目录,用于存放配置脚本等等

/home/alipay/web/

script/ web/ db.sqlite3 manage.py uwsgi.ini

第三步:编辑uwsgi.ini文件内容如下: 目录参考个人目录进行修改

```shell

# uwsig使用配置文件启动

[uwsgi]

# 项目目录

chdir=/home/alipay/web/

# 指定项目的application

module=web.wsgi:application

# 指定sock的文件路径

socket=/home/alipay/web/script/uwsgi.sock

# 进程个数

workers=5

pidfile=/home/alipay/web/script/uwsgi.pid

# 指定IP端口

http=0.0.0.0:8000

# 指定静态文件

#static-map=/static=/home/alipay/web/static/

# 启动uwsgi的用户名和用户组

uid=www-data

gid=www-data

# 启用主进程

master=true

# 自动移除unix Socket和pid文件当服务停止的时候

vacuum=true

# 序列化接受的内容,如果可能的话

thunder-lock=true

# 启用线程

enable-threads=true

# 设置自中断时间

harakiri=30

# 设置缓冲

post-buffering=4096

# 设置日志目录

daemonize=/home/alipay/web/script/uwsgi.log

# 权限

chmod-socket = 666

chown-socket = www-data

```

#### 5.执行命令,启动项目测试

uwsgi --ini uwsgi.ini

在浏览器访问127.0.0.1:8000

#### 6,安装nginx

1.安装nginx

sudo apt-get install python-dev nginx

2.安装完成后,可以使用通过浏览器访问公网IP测试

3.创建项目的配置文件,或者直接修改原nginx配置文件都可以

vim /etc/nginx/sites-available/webtest.conf

```nginx文件内容根据个人情况自行调整

server {

listen 80;

server_name localtion;

charset utf-8;

client_max_body_size 75M;

location / {

uwsgi_pass unix:///home/alipay/web/script/uwsgi.sock;

include /etc/nginx/uwsgi_params;

}

#location /media {

# alias /path/to/project/media;

#}

location /static {

alias /home/alipay/web/static/;

}

}

```

4.创建完配置文件后创建软连接

sudo ln -s /etc/nginx/sites-available/webtest.conf /etc/nginx/sites-enabled/webtest.conf

5.启动nginx,重新加载配置文件

nginx -s reload

#### 注意:

1.给当前项目设置访问权限。www-data

2.注意在nginx的配置中uwsgi_pass这一项

uwsgi_pass unix:///home/yc/web/script/uwsgi.sock;

它需要找到你在启动uwsgi后的sock文件,并且要注意权限

3.在使用uwsgi --ini uwsgi.ini启动后会创建 .sock文件

那么在后面更新代码时不需要把 script目录下的文件都删除

只需要重启即可

uwsgi --reload xxx.pid

掌握学习方法,不如会弯道超车!

学习猿地:成就自己的只需一套精品!

标签: #ecsnginxuwsgi