文章目录
- 1. Node.JS 模块系统
- 2. npm使用介绍
- 3. 搭建第一个服务端应用
- 4. GET / POST请求
- 5. Web 前后端分离
- 6. 使用Express框架搭建Web服务
- 7. Request 和 Response
- 8. 中间件
- 9. 使用 Koa 框架搭建Web服务
- 10. 使用 Egg 框架搭建Web服务
- 11. egg 项目结构大全
注意:本次教程注重Node.JS 的Web项目文件结构和开发过程,不涉及基本语法
1. Node.JS 模块系统
导出模块
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello; // 将函数Hello暴露出来
引入模块
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
2. npm使用介绍
有时候我们不仅需要引入自己的模块,还要借用别人的模块,这就需要NPM
NPM是随同NodeJS一起安装的包管理工具,可以获取别人已经实现的代码。
npm可以分为全局安装和本地安装
# 本地安装
# 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),
# 如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。
# 可以通过 require() 来引入本地安装的包。
npm install express
# 全局安装
# 将安装包放在 /usr/local 下或者你 node 的安装目录。
# 可以直接在命令行里使用。
npm install express -g
调用express工具
var express = require('express');
var app = express();
// 开启服务之后,如果访问到了/,就发生下面的函数
app.get('/', function (req, res) {
res.send('Hello World');
})
// 监听器,监听到8081端口有动静就触发回调函数
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
3. 搭建第一个服务端应用
// 使用require指令加载模块
var http = require('http');
// 使用http.createServer()方法创建服务器
http.createServer(function (request, response) {
// 通过request、response参数来接口和响应数据
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8888);
console.log('Server running at http://127.0.0.1:8888/');
4. GET / POST请求
获取GET请求URL的参数
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
res.write("网站名:" + params.name);
res.write("\n");
res.write("网站 URL:" + params.url);
res.end();
}).listen(3000);
获取POST请求内容
var http = require('http');
var querystring = require('querystring');
var postHTML =
'<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js 实例</title></head>' +
'<body>' +
'<form method="post">' +
'网站名: <input name="name"><br>' +
'网站 URL: <input name="url"><br>' +
'<input type="submit">' +
'</form>' +
'</body></html>';
http.createServer(function (req, res) {
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
// 解析参数
body = querystring.parse(body);
// 设置响应头部信息及编码
res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
if(body.name && body.url) { // 输出提交的数据
res.write("网站名:" + body.name);
res.write("<br>");
res.write("网站 URL:" + body.url);
} else { // 输出表单
res.write(postHTML);
}
res.end();
});
}).listen(3000);
5. Web 前后端分离
server.js
var http = require('http');
var fs = require('fs');
var url = require('url');
// 创建服务器
http.createServer( function (request, response) {
// 解析请求,包括文件名
var pathname = url.parse(request.url).pathname;
// 输出请求的文件名
console.log("Request for " + pathname + " received.");
// 从文件系统中读取请求的文件内容
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP 状态码: 404 : NOT FOUND
// Content Type: text/html
response.writeHead(404, {'Content-Type': 'text/html'});
}else{
// HTTP 状态码: 200 : OK
// Content Type: text/html
response.writeHead(200, {'Content-Type': 'text/html'});
// 响应文件内容
response.write(data.toString());
}
// 发送响应数据
response.end();
});
}).listen(8080);
// 控制台会输出以下信息
console.log('Server running at http://127.0.0.1:8080/');
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h1>我的第一个标题</h1>
<p>我的第一个段落。</p>
</body>
</html>
接着我们在浏览器中打开地址:http://127.0.0.1:8080/index.html
6. 使用Express框架搭建Web服务
Express是一个简洁的node.js Web应用框架,提供了一系统强大特性帮助你创建各种Web应用,使用Express可以快速地搭建一个完整功能的网站。
var express = require('express');
var app = express();
// 主页输出 "Hello World"
app.get('/', function (req, res) {
console.log("主页 GET 请求");
res.send('Hello GET');
})
// POST 请求
app.post('/', function (req, res) {
console.log("主页 POST 请求");
res.send('Hello POST');
})
// /del_user 页面响应
app.get('/del_user', function (req, res) {
console.log("/del_user 响应 DELETE 请求");
res.send('删除页面');
})
// /list_user 页面 GET 请求
app.get('/list_user', function (req, res) {
console.log("/list_user GET 请求");
res.send('用户列表页面');
})
// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {
console.log("/ab*cd GET 请求");
res.send('正则匹配');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
接下来你可以尝试访问 http://127.0.0.1:8081 不同的地址,查看效果。
在浏览器中访问 http://127.0.0.1:8081/list_user,结果如下图所示:
7. Request 和 Response
Request 对象 - request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性。常见属性有:
req.app:当callback为外部文件时,用req.app访问express的实例
req.baseUrl:获取路由当前安装的URL路径
req.body / req.cookies:获得「请求主体」/ Cookies
req.fresh / req.stale:判断请求是否还「新鲜」
req.hostname / req.ip:获取主机名和IP地址
req.originalUrl:获取原始请求URL
req.params:获取路由的parameters
req.path:获取请求路径
req.protocol:获取协议类型
req.query:获取URL的查询参数串
req.route:获取当前匹配的路由
req.subdomains:获取子域名
req.accepts():检查可接受的请求的文档类型
req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
req.get():获取指定的HTTP请求头
req.is():判断请求头Content-Type的MIME类型
Response 对象 - response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据。常见属性有:
res.app:同req.app一样
res.append():追加指定HTTP头
res.set()在res.append()后将重置之前设置的头
res.cookie(name,value [,option]):设置Cookie
opition: domain / expires / httpOnly / maxAge / path / secure / signed
res.clearCookie():清除Cookie
res.download():传送指定路径的文件
res.get():返回指定的HTTP头
res.json():传送JSON响应
res.jsonp():传送JSONP响应
res.location():只设置响应的Location HTTP头,不设置状态码或者close response
res.redirect():设置响应的Location HTTP头,并且设置状态码302
res.render(view,[locals],callback):渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
res.send():传送HTTP响应
res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
res.set():设置HTTP头,传入object可以一次设置多个头
res.status():设置HTTP状态码
res.type():设置Content-Type的MIME类型
8. 中间件
app.use(a):注册a中间件,之后的app都会先执行a中间件
app.use(“/home”,a):表示只响应后缀为/home的路径
9. 使用 Koa 框架搭建Web服务
Koa 是由Express原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的Web框架。
Koa 增加了一个Context的对象,作为这次请求的上下文对象(在koa2中作为中间件的第一个参数传入)。同时Context上也挂载了Request和Response两个对象。
Koa的基本使用
实现增删改查
const Koa = require("koa")
const Router = require("koa-router") // 因为Koa没有路由,所以需要引入Koa-router
const app = new Koa()
const router = new Router()
router.post("/list",(ctx, next) => {
// ctx.response.body简写成ctx.body
ctx.body = { ok: 1, info:"add list success" }
})
router.get("/list",(ctx, next) => {
ctx.body = ["111","222","333"]
})
router.put("/list/:id", (ctx, next) => {
console.log(ctx.params)
ctx.body = { ok: 1, info:"put list success" }
})
router.del("/list/:id", (ctx, next) => {
ctx.body = { ok: 1, info:"del list success" }
})
app.use(router.routes()) // 注册路由中间件
app.use(router.allowedMethods()) // 当请求方法错误时,提示相应错误
app.listen(3000)
Koa 路由文件拆分
将上述代码中的路由提取出来统一管理。
index.js
const Koa = require("koa")
const Router = require("koa-router")
const app = new Koa()
const router = new Router()
const userRouter = require("./routes/user") // 导入user路由表
const listRouter = require("./routes/list") // 导入list路由表
// 先注册路由级中间件,遇到url就调用对应的routes
router.use("/user", userRouter.routes(),userRouter.allowedMethods())
router.use("/list",listRouter.routes(),listRouter.allowedMethods())
// 任何访问都要经过这个中间件
app.use(router.routes())
// 当请求方法错误时(比如需要get请求发成了post请求),提示相应错误
app.use(router.allowedMethods())
app.listen(3000)
user.js
const Router = require("koa-router")
const router = new Router()
router.post("/",(ctx, next) => {
ctx.body = {
ok: 1,
info:"add user success"
}
})
router.get("/",(ctx, next) => {
ctx.body = ["111","222","333"]
})
router.put("/:id", (ctx, next) => {
console.log(ctx.params)
ctx.body = {
ok: 1,
info:"put user success"
}
})
router.del("/:id", (ctx, next) => {
ctx.body = {
ok: 1,
info:"del user success"
}
})
module.exports = router
list.js
const Router = require("koa-router")
const router = new Router()
router.post("/",(ctx, next) => {
ctx.body = {
ok: 1,
info:"add list success"
}
})
router.get("/",(ctx, next) => {
ctx.body = ["111","222","333"]
})
router.put("/:id", (ctx, next) => {
console.log(ctx.params)
ctx.body = {
ok: 1,
info:"put list success"
}
})
router.del("/:id", (ctx, next) => {
ctx.body = {
ok: 1,
info:"del list success"
}
})
module.exports = router
Koa 获取请求参数
1. GET方法
请求对象ctx.query,返回如{ a:1, b:2 }
请求字符串ctx.querystring,返回如a=1&b=2
2. POST方法
对于POST请求的处理,koa-bodyparser中间件可以把koa上下文的formData数据解析到ctx.request.body中
10. 使用 Egg 框架搭建Web服务
Egg.js是nodejs的一个框架,它是基于koa框架的基础之上的上层框架,它继承了Koa。
Express也是Node.js的一个框架,express简单且扩展性强,但是express框架缺少了一些约定,不同的开发者会写出不同的代码,适合做个人项目,不太适合团队开发,而Egg它约定了一些规则,对整个团队开发效率会提高。
Egg 目录结构
egg-demo1
├── app
│ ├── controller
│ │ └── home.js
│ └── router.js
│ ├──public
| | |---css
| | | |-- index.css
| | |---js
| | | |-- index.js
├── config
│ └── config.default.js
└── package.json
Egg 初始化项目
初始化目录结构
$ mkdir egg-demo1
$ cd egg-demo1
$ npm init
$ npm i egg --save
$ npm i egg-bin -- save-dev
在package.json文件中加上 scripts 启动命令
{
"name": "egg-demo1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "egg-bin dev"
},
"author": "",
"license": "ISC",
"dependencies": {
"egg": "^2.14.2"
},
"devDependencies": {
"egg-bin": "^4.9.0"
}
}
在项目中的跟目录新建 app文件夹,再在下面新建 controller文件夹,在该文件夹下新建 home.js
const Controller = require('egg').Controller;
class IndexController extends Controller {
async list() {
const dataList = {
list: [
{ id: 1, title: '今天是我第一天学习egg了', url: '/index/1' },
{ id: 2, title: '今天是我第一次学习egg了', url: '/index/2' }
]
};
await this.ctx.render('index/list.tpl', dataList);
}
}
module.exports = IndexController;
在app文件下新建router.js ,配置路由映射
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/index', controller.index.list);
}
在项目的根目录下新建 config文件夹,在该文件夹下新建 config.default.js
// 下面是我自己的 Cookie 安全字符串密钥
exports.keys = '123456';
// 添加view配置
exports.view = {
defaultViewEngine: 'nunjucks',
mapping: {
'.tpl': 'nunjucks'
}
};
有时候我们需要读取数据后渲染模板,然后呈现给用户,因此我们需要引入对应的模板引擎。因此我们可以使用 Nunjucks 来渲染,先安装对应的插件 egg-view-nunjucks
npm i egg-view-nunjucks --save
安装完成后,我们需要开启插件,因此我们需要在 app/config 下新建 plugin.js 来开启插件配置功能
// app/config/plugin.js
exports.nunjucks = {
enable: true,
package: 'egg-view-nunjucks'
};
为页面编写模板文件,我们一般是放在 app/view 目录下,因此我们需要在app下再新建一个 view文件夹。
<!-- app/view/index/list.tpl -->
<html>
<head>
<title>第一天学习egg</title>
<link rel="stylesheet" href="/public/css/index.css" />
</head>
<body>
<ul class="view-list">
{% for item in list %}
<li class="item">
<a href = "{{ item.url }}">{{ item.title }}</a>
</li>
{% endfor %}
</ul>
</body>
</html>
现在我们运行下 npm run dev 后,访问下:http://127.0.0.1:7001/index 就可以看到如下页面了
11. egg 项目结构大全
egg-project
├── package.json
├── app.js (可选)
├── app
| ├── router.js
│ ├── controller
│ | └── home.js
│ ├── service (可选)
│ | └── user.js
│ ├── middleware (可选)
│ | └── xxx.js
│ ├── schedule (可选)
│ | └── xxx.js
│ ├── public (可选)
│ | └── reset.css
│ ├── view (可选)
│ | └── home.tpl
│ └── extend (可选)
│ ├── helper.js (可选)
│ ├── request.js (可选)
│ ├── response.js (可选)
│ ├── context.js (可选)
│ ├── application.js (可选)
│ └── agent.js (可选)
├── config
| ├── plugin.js
| ├── config.default.js
│ ├── config.prod.js
| ├── config.test.js (可选)
| ├── config.local.js (可选)
| └── config.unittest.js (可选)
└── test
├── middleware
| └── response_time.test.js
└── controller
└── home.test.js
app/router.js 是使用与配置url的路由规则的。
app/controller/** 用于解析用户的输入,处理后返回响应的结果。
app/service/** 用于编写业务逻辑层。
app/middleware/** 用于编写中间件。
app/public/** 用于放置静态资源。
app/extend/** 用于框架的扩展。
config/config.{env}.js 用于编写配置文件。
config/plugin.js 用于编写需要加载的插件。
test/** 一般用于单元测试。
app.js 一般用于启动时候的初始化。
app/view/** 用于放置模板文件,具体是做模板渲染的。
app/model/** 用于放置领域模型,由领域类相关插件约定。如 egg-sequelize