Node_进阶_3
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
})
})
Node_进阶_3的更多相关文章
- Node_进阶_8
Node进阶第八天 一.复习 Node.js特点:单线程.异步I/O(非阻塞I/O).事件驱动(事件环). 适合的程序:就是没有太多的计算,I/O比较多的业务. 举例:留言本.考试系统.说说.图片裁切 ...
- Node_进阶_7
Node进阶第七天 一.复习 一.索引 数据库中,根据一个字段的值,来寻找一个文档,是很常见的操作.比如根据学号来找一个学生.这个学号是唯一的.只要有学号,就能唯一确认一个学生的文档.学号这个属性 ...
- Node_进阶_6
Node进阶第六天 一.复习 cookie是在res中设置,req中读取的.第一次的访问没有cookie. cookie的存储大小有限,kv对儿.对用户可见,用户可以禁用.清除cookie.可以被篡改 ...
- Node_进阶_5
Node进阶第五天 为什么mysql不用开mongod –dbpath xx… 答:因为mysql会在”服务”中运行,也就是开机时自动启动并且长久驻扎在内存中了. mongodb其实也能通过设置来设成 ...
- Node_进阶_4
Node进阶第四天 一.传统数据库技术回顾 数据库就是存储数据的,那么存储数据用txt就行了啊,为什么要有数据库? 理由之一:数据库有行.列的概念,数据有关系,数据不是散的. 老牌数据库,比如Mysq ...
- React-Native进阶_3.触摸高亮显示TouchableHighlight
在安卓原生ListView 点击 其中一个子视图时,会有高亮效果,这个效果在ReactNative 中通过TouchableHighlight 实现,具体使用如下 4.触摸高亮显示 Touchabl ...
- Node_进阶_2
第二天 一.复习: Node.js开发服务器.数据.路由.本地关心效果,交互. Node.js实际上是极客开发出的一个小玩具,不是银弹.有着别人不具备的怪异特点: 单线程.非阻塞I/O.事件驱动. 实 ...
- Node_进阶_1
第一天 1.1简介 Node.js简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,Ryan Dahl把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个让Javascrip ...
- PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)
前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...
随机推荐
- Appstore排名前十的程序员应用软件
程序员又名程序猿,苦逼劳累的代名词,曾经一个朋友这么开玩笑说,如果你是富二代,你当程序员就是脑残,如果你是穷二代,当程序员的话,死的时候一定是趴键盘. 程序员 哦,可怜的程序员.在那山的这边海的那边有 ...
- 【前端分享】 JavaScript最经典的55个技巧(转)
从别的地方看到的,保存下,有空实践下再补充. 1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键 <tab ...
- 优动漫结合Photoshop怎么画草地?
今天继续技法教学~草地的技法,PS教学~但是很简单,都是默认工具,而且是常用工具VS常用设置.你肯定会学会的! 草地教程,就到这里啦!有兴趣的可以尝试画一画哦,想要Get到更多有关优动漫的信息包括软件 ...
- DHCPv6,IPv6的有状态自动配置
DHCPv6,IPv6的有状态自动配置 DHCPv6的工作原理与DHCPv4极其相似,但有一个明显的差别,那就是支持IPV6新增的编址方案.DHCP提供了一些自动配置没有的选项.在自动配置中,根本没有 ...
- Django框架 part 2
web 框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impo ...
- luogu P3387 【模板】缩点_拓扑排序
还是很好些的. Code: #include <stack> #include <cstdio> #include <algorithm> #include < ...
- JS对以对象组成的数组去重
这是从https://segmentfault.com/q/1010000006954351参考的,达到了我要去重的功能!!! var hash = {};//arr是要去重的对象数组 arr = a ...
- javascript编程风格(粗略笔记)
1.空格 紧凑型: project.MyClass = function(arg1, arg2){ 松散型: for( i = 0; i < length; i++ ){ 2.代码行长度 最多8 ...
- POJ 3122 Pie( 二分搜索 )
链接:传送门 题意:一个小朋友开生日派对邀请了 F 个朋友,排队上有 N 个 底面半径为 ri ,高度为 1 的派,这 F 个朋友非常不友好,非得"平分"这些派,每个人都不想拿到若 ...
- HDU 1828 Picture (线段树:扫描线周长)
依然是扫描线,只不过是求所有矩形覆盖之后形成的图形的周长. 容易发现,扫描线中的某一条横边对答案的贡献. 其实就是 加上/去掉这条边之前的答案 和 加上/去掉这条边之后的答案 之差的绝对值 然后横着竖 ...