搭建微信订阅号后台服务

搭建微信订阅号后台服务

准备域名

任务时间:20min ~ 40min

微信公众平台需要配置服务器地址 URL 访问,在实验开始之前,我们要准备域名。

域名注册

如果您还没有域名,可以在腾讯云上选购,过程可以参考下面的视频。

  • 视频 – 在腾讯云上购买域名

域名解析

域名购买完成后, 需要将域名解析到实验云主机上,实验云主机的 IP 为:

<您的 CVM IP 地址>

在腾讯云购买的域名,可以到控制台添加解析记录,过程可参考下面的视频:

  • 视频 – 如何在腾讯云上解析域名

域名设置解析后需要过一段时间才会生效,通过 ping 命令检查域名是否生效 [?],如:

ping www.yourmpdomain.com

如果 ping 命令返回的信息中含有你设置的解析的 IP 地址,说明解析成功。

注意替换下面命令中的 www.yourmpdomain.com 为您自己的注册的域名

申请微信个人订阅号

任务时间:5min ~ 10min

在开始搭建我们的订阅号服务器之前,需要先拿到订阅号相关信息。

注册开发者账号

如果你还不是微信订阅号开发者,请先在微信公众平台注册:

https://mp.weixin.qq.com

具体注册流程可参考如下视频:

  • 视频 – 注册开发者账号

若您已注册,请点击下一步。

获取微信订阅号公众平台认证字段信息

我们需要获取3个字段:AppID Token EncodingAESKey。

登录微信公众平台,依次进入 开发 – 基本配置 可以拿到 AppID。

基本配置 – 服务器配置 – 修改配置 表单中:

URL 填第一步申请的域名;

Token 用户根据提示填写,用于后面校验服务端合法性;

EncodingAESKey 点击随机生成按钮来生成。

当点击表单提交按钮时,微信会通过 Token 来校验 URL 的合法性,这个我们在后面步骤实现,此界面暂时保留不关闭。

AppID Token EncodingAESKey 这3个参数具体的获取步骤也可以参照下面的视频

  • 视频 – 获取微信订阅号信息

搭建 HTTP 服务

任务时间:15min ~ 30min

下面的步骤,将带大家在服务器上使用 Node 和 Express 搭建一个 HTTP 服务器

安装 NodeJS 和 NPM

使用下面的命令安装 NodeJS 和 NPM

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
yum install nodejs -y

安装完成后,使用下面的命令测试安装结果

node -v

编写 HTTP Server 源码

创建工作目录

使用下面的命令在服务器创建一个工作目录:

mkdir -p /data/release/weapp

进入此工作目录

cd /data/release/weapp

创建 package.json

在刚才创建的工作目录创建 package.json,添加我们服务器包的名称和版本号,可参考下面的示例。

示例代码:/data/release/weapp/package.json
{
    "name": "weapp",
    "version": "1.0.0"
}

完成后,使用 Ctrl + S 保存文件

添加 Server 源码

在工作目录创建 app.js,使用 Express.js 来监听 5050 端口[?],可参考下面的示例代码(注:请将 app.js 文件中的token/appid/encodingAESKey等配置项替换为您的订阅号对应的取值)。

示例代码:/data/release/weapp/app.js
// 引用 express 来支持 HTTP Server 的实现
const express = require('express');

// 引用微信公共平台自动回复消息接口服务中间件
var wechat = require('wechat');

// 创建一个 express 实例
const app = express();

// 配置微信公众平台参数,在教程第二步中获取
var config = {
    token: 'your token', // 填第二步中获取的 `token`
    appid: 'your appid', // 填第二步中获取的 `appid`
    encodingAESKey: 'your encodingAESKey', // 填第二步中获取的 `encodingAESKey`
    checkSignature: true // 可选,默认为true。由于微信公众平台接口调试工具在明文模式下不发送签名,所以如要使用该测试工具,请将其设置为false 
};

app.use(express.query());

app.use('/', wechat(config, function (req, res, next) {
    res.reply({
        content: '你好,Hello World!',
        type: 'text'
    });
}));

// 监听端口,等待连接
const port = 5050;
app.listen(port);

// 输出服务器启动日志
console.log(`Server listening at http://127.0.0.1:${port}`);

本实验会以 5050 端口的打开作为实验步骤完成的依据,为了后面的实验步骤顺利进行,请不要使用其它端口号

运行 HTTP 服务

安装 PM2

在开始之前,我们先来安装 [PM2]

npm install pm2 --global

PM2 安装时间可能稍长,请耐心等候 [?]

安装 Express

我们的服务器源码里使用到了 Express 模块,下面的命令使用 NPM 来安装 Express

cd /data/release/weapp
npm install express --save

安装 Wechat

我们的服务器源码里使用到了 Wechat 模块,下面的命令使用 NPM 来安装 Wechat

cd /data/release/weapp
npm install wechat --save

启动服务

安装完成后,使用 PM2 来启动 HTTP 服务

cd /data/release/weapp
pm2 start app.js

现在,您的 HTTP 服务已经在 http://<您的 CVM IP 地址>:5050 运行

要查看服务输出的日志,可以使用下面的命令:

pm2 logs

如果要重启服务,可以使用下面的命令:

pm2 restart app

我们使用 PM2 来进行 Node 进程的运行、监控和管理

NPM 仓库在国内访问速度可能不太理想,如果实在太慢可以尝试使用 CNPM 的 Registry 进行安装:npm install pm2 -g --registry=https://r.cnpmjs.org/

搭建 nginx 对外服务

任务时间:15min ~ 30min

NodeJs只是侦听的机器上的 5050 端口,我们使用 nginx 侦听 80 端口提供对外域名服务

安装 Nginx

在 CentOS 上,可直接使用 yum 来安装 Nginx

yum install nginx -y

安装完成后,使用 nginx 命令启动 Nginx:

nginx

此时,访问 http://<您的域名> 可以看到 Nginx 的测试页面 [?]

如果无法访问,请重试用 nginx -s reload 命令重启 Nginx

配置 HTTP 反向代理

外网用户访问服务器的 Web 服务由 Nginx 提供,Nginx 需要配置反向代理才能使得 Web 服务转发到本地的 Node 服务。

Nginx 配置目录在 /etc/nginx/conf.d,我们在该目录创建 wechat.conf

示例代码:/etc/nginx/conf.d/wechat.conf
server {
        listen 80;
        server_name www.example.com; # 改为第一步申请的域名

        location / {
            proxy_pass http://127.0.0.1:5050;
        }
    }

按 Ctrl + S 保存配置文件,让 Nginx 重新加载配置使其生效:

nginx -s reload

在浏览器通过 http 的方式访问你解析的域名来测试 HTTP 是否成功启动

使用Server端回复微信消息

任务时间:1min ~ 5min

提交服务端配置

我们将第二步微信公众平台中保留的表单提交,同时将 基本配置 – 服务器配置 启用

关注、发送与消息回复

首先通过二维码关注微信订阅号

在聊天界面向微信公众号发送一条消息

最终我们会回到一条 你好,Hello World! 的回复

大功搞成

恭喜!您已经完成了搭建微信订阅号后台服务的实验内容!您可以留用或者购买 Linux 版本的 CVM 继续学习。

Express 入门

Express 入门

安装 NodeJS

任务时间:5min ~ 10min

安装 NodeJS

在终端中,使用下面的命令安装 NodeJS:

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
yum -y install nodejs

安装完成后,可使用下面的命令测试安装结果:

node -v

安装 Express

任务时间:5min ~ 10min

创建工作目录

使用下面的命令在服务器创建一个工作目录:

mkdir -p /data/release/hello

进入此工作目录:

cd /data/release/hello

初始化项目

通过 npm init 命令为你的应用创建一个 package.json 文件。欲了解 package.json 是如何起作用的,请参考 Specifics of npm’s package.json handling

npm init

此命令将要求你输入几个参数,例如此应用的名称和版本。 除 entry point: (index.js) 参数外,其他参数你可以直接按 “回车” 键接受默认设置即可。

对于 entry point: (index.js) 参数,键入 app.js 或者你所希望的名称,这是当前应用的入口文件;如果你希望采用默认的 index.js 文件名,只需按 “回车” 键即可。

安装 Express

接下来安装 Express 并将其保存到依赖列表中:

npm install express --save

如果只是临时安装 Express,不想将它添加到依赖列表中,只需略去 --save 参数即可 [?]

npm install express

安装 Node 模块时,如果指定了 --save 参数,那么此模块将被添加到 package.json 文件中 dependencies 依赖列表中。 然后通过 npm install 命令即可自动安装依赖列表中所列出的所有模块。

Hello world

任务时间:5min ~ 10min

创建 app.js

在 hello 目录中,创建 app.js,然后将下列代码复制进去:

示例代码:/data/release/hello/app.js
var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

var server = app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

完成后,使用 Ctrl + S 保存文件。

[?] 上面的代码启动一个服务并监听从 3000 端口进入的所有连接请求。他将对所有 (/) URL 或 路由 返回 “Hello World!” 字符串。对于其他所有路径全部返回 404 Not Found 。

req (请求) 和 res (响应) 与 Node 提供的对象完全一致,因此,你可以调用 req.pipe()、req.on(‘data’, callback) 以及任何 Node 提供的方法。

启动应用

通过如下命令启动此应用:

node app.js

然后在浏览器中打开 http://<您的 CVM IP 地址>:3000 并查看输出结果。

(如果访问不成功,可能是机器安全组禁用了 3000 端口所致,你可以前往控制台修改安全组配置。)

该步骤完成后,可使用 Ctrl + C 终止运行。

Express 应用生成器

任务时间:5min ~ 10min

安装 Express 应用生成器

通过应用生成器工具 express 可以快速创建一个应用的骨架。

通过如下命令安装:

npm install express-generator -g

-h 选项可以列出所有可用的命令行选项:

express -h

将得到输出:

  Usage: express [options] [dir]

  Options:

    -h, --help          output usage information
    -V, --version       output the version number
    -e, --ejs           add ejs engine support (defaults to jade)
        --hbs           add handlebars engine support
    -H, --hogan         add hogan.js engine support
    -c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git           add .gitignore
    -f, --force         force on non-empty directory

创建项目

进入工作目录:

cd /data/release

执行如下命令,在当前工作目录下创建一个命名为 myapp 的应用:

express myapp

完成后,点击查看 myapp 项目

生成的应用程序具有以下目录结构:

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug

7 directories, 9 files

启动应用

进入该应用目录:

cd myapp

然后安装所有依赖包:

npm install

启动这个应用(MacOS 或 Linux 平台)[?]

DEBUG=myapp npm start

然后在浏览器中打开 http://<您的 CVM IP 地址>:3000 网址就可以看到这个应用了。

(该步骤完成后,可使用 Ctrl + C 终止运行。)

Windows 平台使用如下命令:set DEBUG=myapp & npm start

基本路由

任务时间:10min ~ 15min

Express 路由简介

路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问。

每一个路由都可以有一个或者多个处理器函数,当匹配到路由时,这些函数将被执行。

路由的定义由如下结构组成:

app.METHOD(PATH, HANDLER)

其中:

  • app 是一个 express 实例;
  • METHOD 是某个 HTTP 请求方式 中的一个
  • PATH 是服务器端的路径;
  • HANDLER 是当路由匹配到时需要执行的函数。

一个简单的 Express 路由

修改 hello 项目

返回开始创建的 hello 项目:

cd /data/release/hello

编辑 app.js,参考修改如下:

示例代码:/data/release/hello/app.js
var express = require('express');
var app = express();

// 对网站首页的访问返回 "Hello World!" 字样
app.get('/', function (req, res) {
  res.send('Hello World!');
});

// 网站首页接受 POST 请求
app.post('/', function (req, res) {
  res.send('Got a POST request');
});

// /user 节点接受 PUT 请求
app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user');
});

// /user 节点接受 DELETE 请求
app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user');
});

var server = app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

启动应用

node app.js

(该步骤完成后,可使用 Ctrl + C 终止运行。)

测试

你可以使用 curl 命令或 Postman 等工具进行测试。

如在本地终端执行:

curl -X POST http://<您的 CVM IP 地址>:3000
curl -X PUT http://<您的 CVM IP 地址>:3000/user
curl -X DELETE http://<您的 CVM IP 地址>:3000/user

静态文件

任务时间:5min ~ 10min

利用 Express 托管静态文件

通过 Express 内置的 express.static 可以方便地托管静态文件,例如图片、CSS、JavaScript 文件等。

创建静态目录

创建 public 目录:

mkdir -p /data/release/hello/public

在 public 目录下,创建 hello.html,然后复制下列代码到 hello.html 中:

示例代码:/data/release/hello/public/hello.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <h1>Hello World</h1>
</body>
</html>

修改应用

编辑 app.js,参考修改如下:

示例代码:/data/release/hello/app.js
var express = require('express');
var app = express();

app.use(express.static('public'));

var server = app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

我们在 app.js 中将静态资源文件所在的目录作为参数传递给 express.static 中间件,这样就可以提供静态资源文件的访问了。

启动应用

node app.js

在浏览器中打开 http://<您的 CVM IP 地址>:3000/hello.html 网址就可以看到这个文件了。

你还可以将本地的文件通过拖拽至左边目录树的 public 目录上传文件来测试。

假设在 public 目录放置了图片、CSS 和 JavaScript 文件,你就可以从浏览器中访问:

http://<您的 CVM IP 地址>:3000/images/kitten.jpg
http://<您的 CVM IP 地址>:3000/css/style.css
http://<您的 CVM IP 地址>:3000/js/app.js
http://<您的 CVM IP 地址>:3000/images/bg.png
http://<您的 CVM IP 地址>:3000/hello.html

static 中间件更多用法

多个目录

如果你的静态资源存放在多个目录下面,你可以多次调用 express.static 中间件:

app.use(express.static('public'));
app.use(express.static('files'));

访问静态资源文件时,express.static 中间件会根据目录添加的顺序查找所需的文件。

指定路径

如果你希望所有通过 express.static 访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:

编辑 app.js,参考修改如下:

示例代码:/data/release/hello/app.js
var express = require('express');
var app = express();

app.use('/static', express.static('public'));

var server = app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

启动应用:

node app.js

现在,你就可以通过带有 “/static” 前缀的地址来访问 public 目录下面的文件了。如:

http://<您的 CVM IP 地址>:3000/static/hello.html

完成

任务时间:1min

完成实验

恭喜!您已经完成了 Express 入门的全部实验内容!

更多 Express 相关资料,请查看 Express 官网 。

6 Must Have Node.js Modules

So you’re thinking about using node.js: awesome. If you’re new to the community you’re probably thinking “what’s the best node.js module / library for X?” I think it’s really true when experienced language gurus say “80% of your favorite language is your favorite library.” This is the first in a series of articles will give you a high-level overview of some of our favorite node.js libraries at Nodejitsu. Today we’ll take a look at these libraries:

 

  1. cradle: A high-level, caching, CouchDB library for Node.js
  2. findit: Walk a directory tree in node.js
  3. node_redis: Redis client for node
  4. node-static: RFC2616 compliant HTTP static-file server module, with built-in caching.
  5. optimist: Light-weight option parsing for node.js
  6. xml2js: Simple XML to JavaScript object converter.

 

cradle: A high-level, caching, CouchDB library for Node.js

If you’re using CouchDB you should be using cradle. Cradle stands above the other CouchDB libraries in the node.js community: it has a robust LRU (least recently used) cache, bulk document processing, and a simple and elegant API:

 

//
// Create a connection
//
var conn = new(cradle.Connection)('http://living-room.couch', 5984, {
  cache: true,
  raw: false
});

//
// Get a database
//
var database = conn.database('newyorkcity');

//
// Now work with it
//
database.save('flatiron', {
  description: 'The neighborhood surrounding the Flatiron building',
  boundaries: {
    north: '28 Street',
    south: '18 Street',
    east: 'Park Avenue',
    west: '6 Avenue'
  }
}, function (err, res) {
  console.log(res.ok) // True
});

 

 

findit: Walk a directory tree in Node.js

A common set of problems that I see on the nodejs mailing list are advanced file system operations: watching all the files in a directory, enumerating an entire directory, etc. Recently, when working on my fork of docco to respect directory structure in the documentation produced I needed such a feature. It was surprisingly easy:

 

var findit = require('findit');

findit.find('/dir/to/walk', function (file) {
  //
  // This function is called each time a file is enumerated in the dir tree
  //
  console.log(file);
});

 

 

node_redis: Redis client for Node.js

There have been a lot of redis clients released for node.js. The question has become: which client is the right one to use? When selecting an answer to this question for any library you want to look for a few things including: the author, the recent activity, and the number of followers on GitHub. In this case the author is Matt Ranney, a member of the node.js core team. The most recent commit was yesterday, and the repository has over 300 followers.

Redis is really fast, and extremely useful for storing volatile information like sessions and cached data. Lets take a look at some sample usage:

 

var redis = require("redis"),
    client = redis.createClient();

client.on("error", function (err) {
  console.log("Error " + err);
});

client.set("string key", "string val", redis.print);
client.hset("hash key", "hashtest 1", "some value", redis.print);
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
client.hkeys("hash key", function (err, replies) {
  console.log(replies.length + " replies:");
  replies.forEach(function (reply, i) {
      console.log("    " + i + ": " + reply);
  });
  client.quit();
});

 

 

node-static: RFC2616 compliant HTTP static-file server module, with built-in caching

I bet you’re wondering “What the $%^@ is RFC2616?” RFC2616 is the standards specification for HTTP 1.1, released in 1999. This spec is responsible for outlining how (among other things) files should be served over HTTP. Thus, when choosing a node.js static file server, its important to understand which libraries are standards compliant and which are not: node-static is. In addition, it has some great built-in caching which will speed up your file serving in highly concurrent scenarios.

Using node-static is easy, lets make a static file server in 7 lines of Javascript:

 

var static = require('node-static');

//
// Create a node-static server instance to serve the './public' folder
//
var file = new(static.Server)('./public');

require('http').createServer(function (request, response) {
  request.addListener('end', function () {
    //
    // Serve files!
    //
    file.serve(request, response);
  });
}).listen(8080);

 

 

optimist: Light-weight option parsing for Node.js

One of the great things about node.js is how easy it is to write (and later publish with npm) simple command-line tools in Javascript. Clearly, when one is writing a command line tool one of the most important things is to have a robust command line options parser. Our library of choice for this at Nodejitsu is optimist by substack.

Lets take a look at a sample CLI script reminiscent of FizzBuzz:

 

#!/usr/bin/env node
var argv = require('optimist').argv;

if (argv.rif - 5 * argv.xup > 7.138) {
  console.log('Buy more riffiwobbles');
}
else {
  console.log('Sell the xupptumblers');
}

 

Using this CLI script is easy:

$ ./node-optimist.js --rif=55 --xup=9.52
Buy more riffiwobbles

$ ./node-optimist.js --rif 12 --xup 8.1
Sell the xupptumblers

This library has support for -a style arguments and --argument style arguments. In addition any arguments passed without an option will be available in argv._. For more information on this library check out the repository on GitHub.

 

xml2js: Simple XML to Javascript object converter

Writing clients in node.js for APIs that expose data through JSON is almost too easy. There is no need for a complex, language-specific JSON parsing library that one might find in languages such as Ruby or Python. Just use the built-in Javascript JSON.parse method on the data returned and voila! you’ve got native Javascript objects.

But what about APIs that only expose their data through XML? You could use the native libxmljsmodule from polotek, but the overhead of dealing with individual XML nodes is non-trivial and (in my opinion) can lead to excess complexity. There is another, simpler option: the lesser knownxml2js library available on npm and GitHub.

Lets suppose that we had some XML (/me dies a little inside):

 

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <child foo="bar">
    <grandchild baz="fizbuzz">grandchild content</grandchild>
  </child>
  <sibling>with content!</sibling>
</root>

 

Parsing this using xml2js is actually surprisingly easy:

 

var fs = require('fs'),
    eyes = require('eyes'),
    xml2js = require('xml2js');

var parser = new xml2js.Parser();

parser.on('end', function(result) {
  eyes.inspect(result);
});

fs.readFile(__dirname + '/foo.xml', function(err, data) {
  parser.parseString(data);
});

 

The output we would see is:

 

{
  child: {
    @: { foo: 'bar' },
    grandchild: {
      #: 'grandchild content',
      @: { baz: 'fizbuzz' }
    }
  },
  sibling: 'with content!'
}

 

If you haven’t already noticed, xml2js transforms arbitrary XML to JSON in the following way:

  • All entity tags like <child> become keys in the corresponding JSON.
  • Simple tags like <sibling>with content</sibling> become simple key:value pairs (e.g. sibling: ‘with content!’)
  • More complex tags like <child>... and <grandchild>... become complex key:value pairs where the value is an Object literal with two important properties:
    1. @: An Object representing all attributes on the specified tag
    2. #: Any text content for this XML node.

This simple mapping can greatly simplify the XML parsing logic in your node.js application and is worth checking out if you ever have to deal with the three-headed dog we all love to hate.

 

Just getting started

This is the first in a series of articles where we will outline at a high level the best-of-the-best for modules, libraries and techniques in node.js that you should be aware of. If you’re interested in writing your own node.js modules and publishing them to npm, check out isaacs new article: How to Module over at howtonode.org.