服务端搭建
一、环境准备
1.操作系统与网络
本文以Arch Linux为例,在VirtualBox虚拟机下运行,通过SSH与宿主机连接。
由于虚拟机通过NAT联网,要想访问在虚拟机中部署的Web服务需要进行端口转发:
- 打开VirtualBox管理器,进入Arch虚拟机的设置页,在网络选项卡中点击高级
- 点击端口转发,我们新建一个端口转发规则。协议为
TCP
;主机IP填写VirtualBox虚拟网卡的地址,在Windows宿主机通过ipconfig
命令可查看,默认为192.168.56.1
;子系统IP填写虚拟机IPv4地址,在Arch虚拟机中通过ip addr
命令可查看(图中红框所示处);子系统端口为我们即将部署的Node服务的监听端口;主机端口为转发到主机后的端口,我们应该避开常用或已被占用的端口(如21、22、25、80、443),为了方便我们可以转发到原端口,本文以3000端口为例 - 这样设置完毕后虚拟机的3000端口就可以通过
192.168.56.1:3000
访问了2.Node.js
由于该虚拟机此前已安装Node.js、MongoDB等,首先将其卸载再做演示:1
pacman -Rsc nodejs mongodb #删除Node.js、MongoDB和所有依赖这两个软件包的程序
更多关于pacman
(Arch官方软件包管理器)的用法请见这里
通过pacman
安装Node.js:1
pacman -S nodejs npm #安装node及包管理器npm
或者从Node.js官网下载二进制文件:1
2
3 wget https://nodejs.org/dist/v8.12.0/node-v8.12.0-linux-x64.tar.xz
xz -d node-v8.12.0-linux-x64.tar.xz
tar -xvf node-v8.12.0-linux-x64.tar
3.MongoDB
- 方法一:
1 | pacman -S mongodb #从官方软件仓库安装mongodb |
Arch Linux的默认dbpath是/var/lib/mongodb/,启动服务后可以通过mongo
命令进入Mongo Shell
- 方法二:
1 | cd /home |
为了快速使用mongodb
命令,可以配置环境变量。编辑~/.profile
或/etc/profile
文件,将mongodb/bin
路径加入即可:1
sudo vim /etc/profile
在文件末尾添加一行:1
export PATH=$PATH:/home/mongodb-linux-x86_64-4.0.2/bin
保存修改后,在终端运行以下命令使环境变量生效:1
source /etc/profile
启动mongod
:1
2 mkdir /data/db #创建数据存放目录
mongod --dbpath /data/db
此时mongod
已经启动,我们可以在另一终端中通过mongo
命令进入交互程序
二、部署服务
1.建立应用并安装依赖
首先建立一个工作目录:1
2 mkdir wx
cd wx
通过npm init
初始化一个应用,此时会要求你输入应用的名称、版本、入口文件等信息,可以按Enter
键选择默认值,最终npm
会为你生成一个package.json
文件1
npm init
下面通过Node包管理器安装Express、Mongoose:1
npm install express mongoose --save
安装成功后会出现+ express
、+ mongoose
等字样,这两个包及其所需依赖都被安装在/node_modules
中并被写入package.json
:
除了上述方法,我们也可以通过全局安装来达到一劳永逸的目的:
1 | npm install express mongoose -g |
2.建立HWMongo模块
编辑hwmongo.js
:1
vim hwMongo.js
将数据库连接与定义Schema部分写进hwMongo.js
,以便后续调用:1
2
3
4
5
6
7
8
9
10
11//hwmongo.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test'); //与数据库建立连接
var helloWorldSchema = mongoose.Schema({
country: String,
helloWorld: String,
}); //定义数据架构helloWorldSchema
var HWMongo = mongoose.model('HWs', helloWorldSchema);
module.exports = HWMongo; //导出HWMongo
3.初始化数据
编辑initData.js
:1
vim initData.js
将初始数据插入文档: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
26var HWMongo = require('./hwMongo');
new HWMongo({
country: 'China',
helloWorld: '你好,世界!'
}).save();
new HWMongo({
country: 'US',
helloWorld: 'Hello World!'
}).save();
new HWMongo({
country: 'Danmark',
helloWorld: 'Hallo, Verden!'
}).save();
new HWMongo({
country: 'Germany',
helloWorld: 'Hallo, Welt!'
}).save();
new HWMongo({
country: 'France',
helloWorld: 'Bonjour, tout le monde'
}).save();
运行程序:1
node initData.js
如果出现“当前URL解析器被弃用”的警告,我们可以修改hwMongo.js
的数据库连接部分(第3行),使用新的解析器:1
mongoose.connect('mongodb://localhost/test', {useNewUrlParser: true}); //Line 3
数据初始化完成之后我们可以通过mongo
进入Mongo Shell,在交互程序中通过use wx
切换至数据库“wx”,通过show collections
可以列出数据库中的全部集合,通过db.hws.find()
可以进行查询:1
2
3
4
5
6
7
8
9
10> use wx
switched to db wx
> show collections
hws
> db.hws.find()
{ "_id" : ObjectId("5bb597c822106c03e8e75b72"), "country" : "US", "helloWorld" : "Hello World!", "__v" : 0 }
{ "_id" : ObjectId("5bb597c822106c03e8e75b73"), "country" : "Danmark", "helloWorld" : "Hallo, Verden!", "__v" : 0 }
{ "_id" : ObjectId("5bb597c822106c03e8e75b74"), "country" : "Germany", "helloWorld" : "Hallo, Welt!", "__v" : 0 }
{ "_id" : ObjectId("5bb597c822106c03e8e75b75"), "country" : "France", "helloWorld" : "Bonjour, tout le monde", "__v" : 0 }
{ "_id" : ObjectId("5bb597c822106c03e8e75b71"), "country" : "China", "helloWorld" : "你好,世界!", "__v" : 0 }
4.建立HTTP服务器
编辑入口文件index.js
:1
vim index.js
在index.js
中编写简易HTTP服务器与查询服务:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const express = require('express');
const HWMongo = require('./hwMongo.js'); //调用模块
const app = express();
const port = 3000; //http服务器端口号
app.get('/country', function(req,res) {
HWMongo.findOne({'country': req.query.country}, function(err, doc) {
if (err) {
console.log("数据库出错");
} else if (doc==null) {
res.send("输入信息有误,请重试");
console.log(req.query.country + ":" + doc);
} else {
res.send(doc.helloWorld); //应答报文
console.log(req.query.country + ":" +doc.helloWorld);
}
});
});
app.listen(port, function() {
console.log('Server is running at http://localhost:3000/.');
});
HTTP服务器跑起来后宿主机所在局域网内的设备可以通过http://192.168.56.1:3000
来访问:1
node index.js
至此,服务端已搭建完成
前端小程序实现
一、开发工具
在这里下载并安装微信web开发者工具
二、项目与项目配置文件
新建一个空白项目,编辑项目配置文件project.config.json
,为了调试方便,我们将urlCheck
一项改为false
:1
2
3
4
5
6
7
8{
...
"setting": {
"urlCheck": false,
...
},
...
}
更多关于项目配置文件的描述请见这里
三、文件结构
从微信小程序官方文档中我们可以知道小程序的文件组成结构,具体内容如下
小程序主体部分(项目根目录下):
文件 | 必需 | 作用 |
---|---|---|
app.js | 是 | 小程序逻辑 |
app.json | 是 | 小程序公共配置 |
app.wxss | 否 | 小程序公共样式表 |
小程序页面:
文件类型 | 必需 | 作用 |
---|---|---|
js | 是 | 页面逻辑 |
wxml | 是 | 页面结构 |
json | 否 | 页面配置 |
wxss | 否 | 页面样式表 |
因此我们在项目目录中新建app.js
和app.json
,并编辑app.json
:
1 | { |
此时开发工具会自动建立pages/index
目录及其页面组成文件,至此只包含一个页面的最小项目的框架搭建完成,其文件结构如下:1
2
3
4
5
6
7
8.
├── app.js
├── app.json
├── pages
│ └── index
│ ├── index.js
│ └── index.wxml
└── project.config.json
四、页面逻辑及生命周期
每个页面的JS文件中通过Page(Object)
函数来注册页面,它接受一个对象
类型参数,指定页面的初始数据、生命周期回调、事件处理函数等。
我在此列举几个主要、常用的对象
参数(详见这里):
属性 | 类型 | 说明 |
---|---|---|
data | 对象 | 页面第一次渲染使用的初始数据,JSON 类型 |
onLoad | 函数 | 页面加载时触发,一个页面只会调用一次 |
onShow | 函数 | 页面显示/切入前台时触发 |
onReady | 函数 | 页面初次渲染完成时触发,一个页面只会调用一次 |
onHide | 函数 | 页面隐藏/切入后台时触发 |
其他 | 任意 | 开发者添加任意函数或数据 |
其中所有函数
类型的参数均为生命周期回调函数
我们编辑pages/index
的页面逻辑文件index.js
:
1 | Page({ |
由于微信小程序支持ECMAScript 6
(ES6
)标准,因此JS代码可以省略语句末的分号;
,并且微信官方所有示例程序均采用省略,因此我们也应该遵循微信小程序的编码规范,语句末省略分号;
五、编译与运行
点击开发者工具工具栏中的编译按钮,即可在左侧的模拟器中看到运行效果:
至此,前端部分建构完成
将服务部署至VPS/云服务器
我们可以把我们建构好的服务部署至服务器以实现公网访问,我将该Node+Express+MongoDB组成的服务端部署在Vultr的VPS上(新加坡机房,用来搭梯子的),由于操作系统是CentOS,在部署过程中部分操作略有不同,在此不再赘述。
部署后将微信小程序中pages/index/index.js
的查询函数中的URL修改为VPS/云服务器的公网IP:端口号,实现了全网访问服务:
至此,最小端到端系统实验完成
总结
本实验使我巩固了Node.js、MongoDB、Linux运维、网络原理等多方面知识,并对微信小程序的开发有了一定了解,增强了我对新事物的探索能力。我将在继续深入钻研既学技术的同时努力接触新技术,让自己的技术栈更加充实