Express框架:
一、 Express框架
Express框架是后台的Node框架,类似于JS中的jquery。
#原生Node开发会有很多问题:
1呈递静态页面很不方便,需要处理每个HTTP请求,还要考虑304问题
2路由处理代码不直观清晰,需要写很多正则表达式和字符串函数
3不能集中精力写业务,要考虑很多其他的东西
我们自己可以把第一天的作业,就是那个静态文件服务封装成为模块。封装的越多,就自己做出了类似Express的东西。
Express的哲学就是在你的想法和服务器之间充当薄薄的一层。这并不意味着它不够健壮,或者没有足够的有用特性,而是尽量少干预你,让你充分表达自己的思想,同时提供一些有用的东西。
整体感知,Express框架:
1.expres惊艳的路由能力
var express = require('express');
var app = express();
app.get('/', (req, res) => {
res.send('你好');
});
app.get('/haha', (req, res) => {
res.send('这是haha页面,哈哈哈');
});
app.get(/^/student/([d]{6})$/, (req, res) => {
//正则中的()表示分组提取 第[0]个
res.send('学生信息,学号' + req.params[0]);
});
//冒号可以被req得到
app.get('/teacher/:gonghao', (req, res) => {
//
res.send('老师信息,工号' + req.params.gonghao);
});
app.listen(2888);
2.Express静态文件的伺服能力。
const express = require('express');
var app = express();
//使用中间件:(在当前目录的public文件夹下有index.html 这时GET / 的时候会自动读出index.html)
app.use(express.static('./public'));
app.get('/haha', (req, res) => {
res.send('haha');
});
app.listen(2888);
3.Express与模板引擎的配合,直观清晰,天呐撸
haha.ejs:
<!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">
<title>Document</title>
</head>
<body>
<h1>哈哈哈哈</h1>
<ul>
<% for(var i = 0;i<news.length;i++){%>
<li>
<%= news[i] %>
</li>
<% } %>
</ul>
</body>
</html>
3.js:
const express = require('express');
var app = express();
app.set('view engine','ejs');
app.get('/',(req,res)=>{
//默认就是views/文件夹下
res.render('haha.ejs',{
news:['我是小新闻啊','我也是啊','天啦噜']
})
});
app.listen(2888);
二、路由
我们学习的是Express4.x和Express3.x差别非常大。
用get请求访问一个网址
app.get(‘网址’,(req,res)=>{
});
app.post(‘网址’,(req,res)=>{
});
restful
如果想除了这个网址的任何methods的请求
app.all(‘/’,(req,res)=>{
})
app.get(‘/AAb’,(req,res)=>{
res.send(‘你好’);
})
实际上小写的访问也行。
所有的GET参数,?都已经被忽略。 锚点#也被忽略
你路由到/a,实际/a?id=2&sex=nan 也能被处理
正则表达式可以被使用。正则表达式中,未知部分用圆括号分组,然后可以用req.params[0]、req.params[1]来获取。
app.get(/^/student/([d]{10})$/,(req,res)=>{
res.send(‘学生信息,学号’ + req.params[0]);
});
冒号是更推荐的写法。
const express = require('express');
var app = express();
app.get('/:username/:oid',(req,res)=>{
var username = req.params.username;
var oid = req.params.oid;
res.write(username);
res.end(oid);
});
app.listen(2888);
表单可以自己提交到自己:
05.js:
const express = require('express');
const app = express();
//设置模板引擎
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('form');
});
app.post('/', (req, res) => {
//将数据添加进入数据库
res.send('成功');
});
app.listen(2888);
适合进行RESTful路由设计。
RESTful路由设计
/students
get 读取学生信息
post 修改学生信息
delete 删除学生信息
【用express来实现非常简单】
app.get、app,post、app,delete...
总结:这节课比较重点的地方是 路由,路由的话,app.get(‘’)这里面可以写正则表达式,用()来捕获,也可以写:,最后用req.params[0] 或者req.params.xxx来获取,推荐的是使用:冒号的方式。
一、 中间件
//这个就叫做中间件
app.get('/',(req,res)=>{
console.log('2');
});
顾名思义,中间件(middleware)作为请求和响应之间的中间人,用于处理HTTP请求,返回特定结果。
如果我的get、post回调函数中,没有next参数,那么匹配上第一个中间件后就不会往下继续匹配了,如果向往下匹配的话,那么需要写next();
app.get('/',(req,res,next)=>{
console.log('1');
next();
});
//这个就叫做中间件
app.get('/',(req,res)=>{
console.log('2');
});
下面两个路由,感觉没有关系:
app.get('/:username/:id', (req, res) => {
console.log('1');
res.send('用户信息'+req.params.username);
});
//这个就叫做中间件
app.get('/admin/login', (req, res) => {
console.log('2');
res.send('管理员登陆');
});
但是实际上冲突了,因为admin可以当作用户名 login可以当作id。
解决方法1:交换位置,也就是说,express中所有的路由(中间件)的顺序至关重要。
匹配上第一个,就不会往下匹配了。具体的网上写,抽象的往下写。
主要规则:(写路由表的时候,越具体的越要往上写,越抽象的越要往下写)
解决方法2:使用next()
const express = require('express');
var app = express();
var a = 100;
//这个就叫做中间件
app.get('/admin/login', (req, res) => {
var username = req.params.username;
//检索数据库,如果username不存在,那么next
if(检索数据库){
console.log('2');
res.send('管理员登陆');
}
else{
next();
}
});
app.get('/:username/:id', (req, res) => {
console.log('1');
res.send('用户信息'+req.params.username);
});
app.listen(2888);
路由get、post这些东西,就是中间件,中间件讲究顺序,匹配上第一个之后就不会往后匹配了。除非写了next()之后才能够继续往后匹配。
app.use:
举例,如果我GET /admin 返回’hello world’ 那么我GET /admin/asd 也会返回’hello world’.
app.use('/admin', function(req, res, next) {
// GET 'http://www.example.com/admin/new/asd/asd'
console.log(req.originalUrl); // '/admin/new'
console.log(req.baseUrl); // '/admin'
console.log(req.path); // '/new/asd/asd'
next();
});
app.use也是一个中间件,它与get和post的不同是,它的网址不是精确匹配的,而是有拓展的。
所以:
app.use(‘/’,(req,res)=>{
})
//这样就会出现骚操作。所有的请求是/的扩展,所以…
但是要写next();否则会卡在这个中间件。
app.use(‘/’,(req,res)=>{
console.log(‘haha’);
next();
})
还可以这样简写:
//不写就相当于‘/’
app.use((req,res)=>{
console.log(‘haha’);
next();
})
app.use()就给我们增加一些特定功能的便利场所。
自带的静态服务:
app.use(express.static(‘./public’));
//使用了app.use这个方法,使用了封装好的express.static这个中间件,这个静态服没有next方法(),一般把它放在代码的上边部分,防止做路由的时候和现有文件冲突,
比如你有一个image文件夹就没必要再做/image路由转到别的地方。直接读这个文件夹就好了。
//其实似乎这两个广义地讲都叫中间件..
(但是我们其实编程时候不怎么使用app.use方法,因为这很不MVC)
app.use(‘/jingtai’,express.static(‘./public’));
·大多数情况下,渲染内容用res.render(),将会根据views中的模板文件进行渲染。如果不想使用view文件夹,想自己设置文件夹名字,那么app.set(‘views’,’…’)
·如果想写一个快速测试页,当然可以使用res.send()。这个函数 将根据内容,自动帮我们设置了Content-Type头部和200状态吗。send()只能用一次,和end一样。和end不一样在哪里?能够自动设置MIME
·如果想使用不同的状态吗,可以:
res.status(404).send(‘Sorry,we cannot find that’)
·如果想使用不同的Content-Type,可以:
res.set(‘Content-Type’,’text,html’);
app.set…
(…这些都可以被set,如果需要使用请详细查看官网文档)
四、GET请求和POST请求
·GET请求的参数在URL中,在原生Node中,需要使用url模块来识别参数字符串。在Express中,不需要使用url模块来parse了,可以直接使用req.query对象。
·POST请求在express中不能直接获得,必须使用body-parser模块,使用后,将可以用req.body得到参数。但是如果表单中含有文件上传,那么还是需要使用formidable模块。
req.query打印出的是一个对象,比如GET ?a=1&b=2 返回的就是:{a:1,b:2}
POST引擎需要引用body-parser中间件
req.body打印出一个对象
12.js:
const express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.set('view engine', 'ejs');
app.get('/', (req, res) => {
res.render('form');
});
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/', (req, res) => {
res.send(req.body);
});
app.listen(3333);
捋捋api:
主要来看一下最后一个Route,Route是个啥.
以下内容摘抄自网络:
———————————————————————————————————————
当你调用 express() 方法时,就创建了一个 Application。事实上这个 Application 也只不过是对 Router 的一个轻量级封装而已。
每个 Application 内部都创建了一个 Router,大部分对 Application 的操作实际上都被重定向到了这个内部的 Router 上而已。而 Application 所做的,只不过是在这个 Router 的基础上添加了一些额外的便捷 API 而已。
举个例子,当你调用 app.get(...) 或者 app.use(...) 的时候,实际上真正调用的是 app._router.get(...) 或者 app_router.use(...)。
所以,Application 和 Router 的区别便很清楚了,Application 是 Router 的一个“包装”,而 Router 才是“核心”。
router.get
is only for defining subpaths. Consider this example:
var router = express.Router();
app.use('/first', router); // Mount the router as middleware at path /first
router.get('/sud', smaller);
router.get('/user', bigger);
Now if you will open /first/sud in your browser, then smaller
function will get called. If you will open first/user, then bigger
will gets called. In short, app.use('/first', router) mounts the middleware at path /first, then router.get
sets the subpath accordingly.
But if we instead use:
app.use('/first', fun);
app.get('/sud', bigger);
app.get('/user', smaller);
Now if you will open /first in your browser then fun
will get called and for /sud, bigger
will get called and for /user, the function smaller
will get called. ...but remember here for /first/sud, no function will get called.
回答者要传达的意思是:“路由级别的中间件,可以作为app级别的中间件的扩展,从而减小app级别路径处理的臃肿,提高可维护性和扩展性”。
强行比喻一下:
产品经理通过应用级别的中间件,控制一级路径;然后各个项目经理,在此基础上,自己通过路由级别的中间件,控制二级路径(项目经理不用考虑产品经理是怎么处理一级路径的)。
——————————————————————————————————
小小相册项目:
//前端语言与后端语言
本质区别:前端是在用户电脑运行,后端是在服务器运行
Node中全是回调函数,所以我们自己封装的函数,里面如果有异步方法,比如I/O,那么就要用回调函数的方法封装。
错误
res.render(“index”,
{“name”:student.getDetailById(234234).name});
正确
student.getDetailByXuHao(234234,function(detail){
res.render(“index”,{
“name”:detail.name
})
})