Node_进阶_3

Express框架:

一、   Express框架

Express框架是后台的Node框架,类似于JS中的jquery。

#原生Node开发会有很多问题:

 1呈递静态页面很不方便,需要处理每个HTTP请求,还要考虑304问题

 2路由处理代码不直观清晰,需要写很多正则表达式和字符串函数

 3不能集中精力写业务,要考虑很多其他的东西

我们自己可以把第一天的作业,就是那个静态文件服务封装成为模块。封装的越多,就自己做出了类似Express的东西。

Express的哲学就是在你的想法和服务器之间充当薄薄的一层。这并不意味着它不够健壮,或者没有足够的有用特性,而是尽量少干预你,让你充分表达自己的思想,同时提供一些有用的东西。

http://www.expressjs.com.cn/

整体感知,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

})

})

原文地址:https://www.cnblogs.com/eret9616/p/9111300.html