图:Anna Paschenko
开通微信支付服务,准备一个可以在互联网上被访问到的开发环境,就可以为应用开发微信支付功能了。下面就一起了解一下搭建开发微信支付环境的方法,然后在一个 Node.js 应用里实现微信支付的扫码支付(Native)功能。
内容比较多,所以分成两个部分,这是上半部分,主要介绍的是微信支付开发前的一些准备工作,在本地搭建一个开发微信支付的环境。文章配套有个视频版本,宁皓网会员可以在线观看:《微信支付:开发准备与扫码支付》。
准备工具
- 命令行工具:Windows 下载安装完整版的 Cmder,macOS 使用系统自带的终端(Terminal),当我在文章里提到打开命令行工具的时候,指的就是打开命令行界面(CLI),意思就是让你打开这两个工具里的其中的一个(Cmder / Terminal)。
- 文本编辑器:我用的是 Atom,在上面安装几个需要的插件(package):
- emmet,可以用缩写形式创建 HTML 与 CSS 代码。
- language-log,高亮显示 log 类型的日志文件。
- edge,高亮显示 edge 模板引擎代码。
- 浏览器:推荐谷歌浏览器(Chrome),或者其它带 Chromium 核心的浏览器。
创建项目
文章里我会在一个 Node.js 应用里实施微信扫码支付的功能,要用的框架是 Adonis.js。确定本地电脑上已经安装好了 Node.js v9.x.x(主要是因为代码里用到了 spread 操作符),推荐使用 NVM 来管理安装的 Node.js,这样可以很容易切换使用不同版本的 Node.js。有了 Node.js,再去安装框架需要的命令行工具。
安装框架命令行
npm install @adonisjs/cli --global
创建项目
使用安装好的 Adonis 框架的命令行工具,去创建一个基于 Adonis 框架的 Node.js 应用。
adonis new ninghao-sandbox-v2
完成以后进入到项目所在的目录,再去运行一下项目。
cd ninghao-sandbox-v2 adonis serve --dev
打开浏览器,访问一下 localhost:3333,可以打开创建的 Adonis 项目。
开发环境
搭建微信支付的开发环境,要保证开发环境可以在互联网上被访问到。因为微信支付系统会通过应用支付的结果,如果开发环境在互联网上不能被访问到,也就收不到这个支付结果。在开发很多其它外部服务的时候,都需要这样做,比如支付宝,微信公众号等等。下面介绍的方法同样适用于搭建开发这些服务的环境。
我用的方法是使用了一台能在互联网上被访问到的服务器,在上面用 Nginx 配置一个代理,把请求转发到服务器的某个端口上。然后用 ssh 在本地跟服务器之间打一个通道,通道用的端口就是配置 Nginx 的时候,设置的上游服务(upstream)的端口。再去设置一个主机名,让它指向服务器,服务器会把请求转发到通道用的端口,这样实际提供服务的就是我们在本地上搭建的开发环境了。
- 准备一台能在互联网上被访问到的服务器,比如阿里云 ECS。
- 设置域名 DNS,让某个主机名指向服务器。
- 配置服务器的 Nginx 代理。
- 在本地电脑上用 ssh 打通道。
服务器
我用了一台阿里云服务器,任何能在互联网上被访问到的服务都可以。服务器的 IP 地址是 42.120.40.68。在本地电脑,使用命令行工具可以登录到服务器。Windows 推荐使用 Cmder 作为命令行工具,macOS 用户可以使用系统自带的终端(Terminal)。
ssh wanghao@42.120.40.68
wanghao 是在我的服务器上的某个用户的名字,这个用户是我自己创建的。一开始,你可以使用服务器的超级管理员:root 登录到你的服务器,然后你可以创建新的用户,为用户分配权限等等。
主机名
配置一个主机名,指向服务器的 IP 地址,这个主机名就是访问本地开发环境用的主机名。我让 sandbox.ninghao.net 这个主机名指向了我的服务器:42.120.40.68。
验证主机名是否已经解析到指定的服务器,可以在命令行下面用 ping 命令测试一下:
→ ping sandbox.ninghao.net PING sandbox.ninghao.net (42.120.40.68): 56 data bytes
用 ping 命令测试 sandbox.ninghao.net 的时候,返回的 IP 地址就是我的服务器的 IP 地址。
Nginx 代理
在服务器上安装 Nginx,再去配置一台 Nginx 代理服务器。我的服务器操作系统是 CentOS 7.x,安装 Nginx ,执行:
# 安装包含 Nginx 的仓库 sudo yum install epel-release -y # 安装 Nginx sudo yum install nginx -y # 启动 Nginx sudo systemctl start nginx # 开机自启动 Nginx sudo systemctl enable nginx
代理配置
在 Nginx 的配置目录的下面,创建一个新的配置文件,放在 /etc/nginx/conf.d,这个目录是 /etc/nginx/nginx.conf 配置文件里面设置的。配置文件所在的目录可能会有变化,比如有可能在 /etc/nginx/sites-enabled 。具体配置文件所在的目录,你要根据自己的实际情况,检查 Nginx 的主配置,就是 nginx.conf 里面的配置。
/etc/nginx/conf.d/sandbox.ninghao.net.conf:
upstream tunnel { server 127.0.0.1:7689; } server { listen 443 ssl; server_name sandbox.ninghao.net; ssl on; client_max_body_size 128m; ssl_certificate /etc/nginx/ssl/sandbox.ninghao.net/214241634170706.pem; ssl_certificate_key /etc/nginx/ssl/sandbox.ninghao.net/214241634170706.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL; ssl_prefer_server_ciphers on; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; expires off; sendfile off; proxy_pass http://tunnel; } }
上面配置了一台服务器,里面用到了 ssl ,这样服务器就支持使用 https 来传输数据了,这是现代网站或应用并且要做的事情。配置 ssl ,你需要申请 ssl 证书,在阿里云,你可以申请免费的 ssl 证书,或者使用 Let's Encrypt ,也可以免费申请到证书。
有了证书,就按上面的配置,证书一般有两个文件,把它们存储在服务器上的某个目录的下面,然后分别设置 ssl_certificate 与 ssl_certificate_key 指令的值。
.key 与 .pem 只是证书惯用的文件扩展名,这个扩展名不重要,重要的是文件里面的内容。.key 指的是证书的密钥,.pem 是证书内容。用 Let's Encrypt 申请的证书,证书文件的扩展名应该是 .cert。
证书密钥
证书密钥文件的扩展名一般是 .key,这个文件里的内容应该作为 Nginx 服务器配置里的 ssl_certificate_key 指令的值。文件里的内容像下面这样:
-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAiDnt/zboVuY23iQBYcocvJSewGDol87FoLOquz61L8rNKc5p ... -----END RSA PRIVATE KEY-----
证书内容
证书内容文件的扩展名一般是 .pem 或者 .cert,文件要作为 Nginx 服务器配置里的 ssl_certificate 指令的值。文件里的内容像下面这样:
-----BEGIN CERTIFICATE----- MIIFgjCCBGqgAwIBAgIQdtV9VRMTtKBDDfN3UO3ujTANBgkqhkiG9w0BAQsFADCB ... -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFYjCCBEqgAwIBAgIQTEzYoPxP6q4VVKh/CQ7ahzANBgkqhkiG9w0BAQsFADCB ... -----END CERTIFICATE-----
重新启动
对 Nginx 服务做了新的配置,要重新加载或者重新启动 Nginx 才能让新的配置生效。执行:
# 检查配置文件是否正常 sudo nginx -t # 重新加载 Nginx sudo systemctl reload nginx
ssh 通道
准备好了服务器,现在要在本地电脑上用 ssh 在本地与服务器之间打个通道。执行:
ssh -vnNT -R 7689:localhost:3333 wanghao@42.120.40.68
7689 ,是通道用的端口,这个端口是在配置 Nginx 的时候设置的,具体是在 upstream 里面设置的:
/etc/nginx/conf.d/sandbox.ninghao.net.conf
upstream tunnel { server 127.0.0.1:7689; }
localhost:3333,这是本地项目服务的地址,就是之前我们创建的那个 Node.js 应用,在本地可以使用这个地址访问到创建的这个应用。
wanghao@42.120.40.68,是登录服务器的时候用的东西,wanghao 是服务器上的某个用户的名字,42.120.40.68 是服务器的 IP 地址,在这台服务器上之前我们已经配置好了 Nginx 。
成功以后,在输出的信息里,你会看到类似下面的字样:
remote forward success for: listen 7689, connect localhost:3333
现在,就可以直接使用 sandbox.ninghao.net 这个主机名,访问到我们在本地开发环境上运行的项目了。
项目路由,控制器,视图
我们的主要目的是去理解微信支付的流程,所以项目本身尽量保持简单。大部分的代码都会放在一个控制器文件里,这样你就很轻松,清楚的知道,实施微信支付的扫码支付,你都需要去做什么。用 Atom 编辑器打开创建的项目目录(ninghao-sandbox-v2)。
路由
先去添加两条路由。
start/routes.js:
Route.get('checkout', 'CheckoutController.render') Route.post('wxpay/notify', 'CheckoutController.wxPayNotify')
/checkout:访问 checkout 这个地址可以显示一个支付用的二维码,用户扫描二维码完成支付。这个地址用 CheckoutController 控制器里的 render 方法来处理。等会儿再去创建它。
/wxpay/notify:用户支付成功以后,微信支付系统会把支付结果异步地通知我们,通知的地址可以使用 /wxpay/notify ,这里用 CheckoutController 控制器里的 wxPayNotify 方法来处理对应用里的这个地址的请求。
控制器
创建路由里面要用的 CheckoutController 控制器,打开命令行,在项目所在目录的下面,执行:
adonis make:controller Checkout
这样会创建一个叫 CheckoutController.js 的文件,位置是:app/Controllers/Http/CheckoutController.js,打开这个控制器文件,在控制器里添加两个方法:
'use strict' class CheckoutController { async render ({ view }) { // 显示支付页面 return view.render('checkout') } async wxPayNotify ({ request }) { // 处理支付结果通知 } } module.exports = CheckoutController
在 render 方法里,指定使用了一个视图。
视图
创建 CheckoutController 里面需要用到的视图。
布局
先在应用里创建一个视图的布局。
resources/views/layouts/main.edge:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> {{ css('https://unpkg.com/bootstrap@4.0.0/dist/css/bootstrap.min.css') }} {{ css('main') }} <title>ninghao</title> </head> <body> @!section('content') {{ script('https://unpkg.com/jquery@3.3.1/dist/jquery.js') }} {{ script('https://unpkg.com/bootstrap@4.0.0/dist/js/bootstrap.min.js') }} {{ script('main') }} </body> </html>
布局里链接使用了 Bootstrap 框架。
@!section('content'),定义了一个 content 区域,在使用了这个布局的地址可以去定义 content 区域里面具体要显示的内容。
css('main') ,链接了一个自定义的样式表叫 main.css,在项目的 public 目录的下面,你可以去创建这个自定义的样式表文件。
{{ script('main') }},在布局中嵌入了一个自定义的脚本文件:main.js,在项目的 public 目录的下面,可以去创建一个 main.js 文件。
视图
再去创建一个视图文件。
resources/views/commerce/checkout.edge:
@layout('layouts.main') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-4"> <div class="card text-center mt-5"> <img class="card-img-top" src="https://ninghao.net/%7B%7B%20assetsUrl%28%27something-wrong.png%27%29%20%7D%7D"> <div class="card-body"> <img class="w-100" src="https://ninghao.net/%7B%7B%20assetsUrl%28%27wxpay.png%27%29%20%7D%7D" /> <p class="card-text"> <small class="text-muted">打开微信,扫码支付</small> </p> </div> </div> </div> </div> </div> @endsection
视图使用了 layouts.main 这个布局,里面定义了布局里的 content 区域要显示的内容。这里用了一个 Bootstrap 的 card 组件,显示的就是一个支付卡片,不过暂时还没有要显示的支付二维码,所以我们用了一个点位符图片(something-wrong.png),以后在应用里生成了支付用的二维码以后,可以用二维码图片替换这个点位符图片的显示。
访问地址:https://sandbox.ninghao.net/checkout
文章下半部分的工作就是去介绍实施微信支付里的扫码支付的细节。订阅宁皓网,可以在线学习微信支付开发的视频课程。
评论
写得太棒了!👍
6 年 9 个月 以前