🦄 2024 独立开发者训练营,一起创业!(早鸟优惠在5天后结束)查看介绍 / 立即报名 →

微信支付:开发准备与实施扫码支付细节手册(上)

图:Anna Paschenko

开通微信支付服务,准备一个可以在互联网上被访问到的开发环境,就可以为应用开发微信支付功能了。下面就一起了解一下搭建开发微信支付环境的方法,然后在一个 Node.js 应用里实现微信支付的扫码支付(Native)功能。

内容比较多,所以分成两个部分,这是上半部分,主要介绍的是微信支付开发前的一些准备工作,在本地搭建一个开发微信支付的环境。文章配套有个视频版本,宁皓网会员可以在线观看:《微信支付:开发准备与扫码支付》。

准备工具

  1. 命令行工具:Windows 下载安装完整版的 Cmder,macOS 使用系统自带的终端(Terminal),当我在文章里提到打开命令行工具的时候,指的就是打开命令行界面(CLI),意思就是让你打开这两个工具里的其中的一个(Cmder / Terminal)。
  2. 文本编辑器:我用的是 Atom,在上面安装几个需要的插件(package):
    1. emmet,可以用缩写形式创建 HTML 与 CSS 代码。
    2. language-log,高亮显示 log 类型的日志文件。
    3. edge,高亮显示 edge 模板引擎代码。
  3. 浏览器:推荐谷歌浏览器(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)的端口。再去设置一个主机名,让它指向服务器,服务器会把请求转发到通道用的端口,这样实际提供服务的就是我们在本地上搭建的开发环境了。

  1. 准备一台能在互联网上被访问到的服务器,比如阿里云 ECS
  2. 设置域名 DNS,让某个主机名指向服务器。
  3. 配置服务器的 Nginx 代理。
  4. 在本地电脑上用 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_certificatessl_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

文章下半部分的工作就是去介绍实施微信支付里的扫码支付的细节。订阅宁皓网,可以在线学习微信支付开发的视频课程

相关资源

  1. 在互联网访问本地开发环境
  2. Adonis.js 框架
  3. Cmder,更好的 Windows 命令行
微信支付

评论

写得太棒了!👍

微信好友

用微信扫描二维码,
加我好友。

微信公众号

用微信扫描二维码,
订阅宁皓网公众号。

240746680

用 QQ 扫描二维码,
加入宁皓网 QQ 群。

统计

14696
分钟
0
你学会了
0%
完成

社会化网络

关于

微信订阅号

扫描微信二维码关注宁皓网,每天进步一点