zoukankan      html  css  js  c++  java
  • Express框架的整体感知

    Express是基于node.js平台的快速、开放、极简的web开放框架,它的地位与作用有点类似于前端的jquery框架。它的英文官网地址为 http://expressjs.com,其对应的中文官网地址为 http://www.expressjs.com.cn 。下面来简单介绍这个框架的用法。

    一、下载及引包

    express作为一个第三方模块包,同样是通过npm的方式进行下载,在当前的项目文件夹下,用命令-> npm install express 来完成下载。再通过 const express = require('express'); 来完成引包。

    二、express提供创建http服务器的功能

    当使用了express这个模块包之后,不再需要引用nodehttp模块,也能提供创建http服务器的功能。其基本的代码段结构为:

    const express = require('express');
    var app = express();
    app.get('/',(req,res)=>{
        res.send('');
    });
    app.listen(3000,'192.168.155.1');

    引包之后返回一个函数体,将该函数体调用执行之后的返回值用app来接收。app类似于创建的那个http服务器实例,该服务器监听IP地址为192.168.155.1,端口号为3000。当浏览器以get方式访问http://192.168.155.1:3000/时,调用执行该回调函数。其中res.send()express内部封装的方法,在其内部可以直接写入返回的字符串参数,不用再用res.writeHead()来设置状态码和mine类型。

    该回调函数内部虽然可以直接使用express自己封装的res.send()方法,不过原生的res.write()res.end()方法仍然可以使用。这三种方法内部参数默认填写字符串类型,如果为其他类型的变量,需要使用.toString()的方法先将其完成类型转换。并且res.send()res.end()均只能出现一次。

    三、express提供强大的路由能力

    上述代码段当中的app.get('/',(req,res)=>{});即为一条路由选择,表示当客户端以get方式访问根目录时,执行该回调函数当中的代码。我们可以以这种方式进行路由选择的设计,客户端访问服务器可以有多种方式,如getpostadddelete等,不过网页端访问一般只有getpost这两种方式,其他的方式一般由app端发起。在浏览器端输入网址、回车、刷新等方式均是默认以get方式进行访问。使用app.all()方法则代表处理这个路由下的任何method请求。

    1、使用冒号语法提取客户端访问的url当中的数据

    示例代码段为:

    const express = require('express');
    var app = express();
    app.get('/:name/:age',(req,res)=>{
        var a = req.params.name;
        var b = req.params.age;
        console.log(a);
        console.log(b);
        res.send();
    });
    app.listen(3000,'192.168.155.1');

    则客户端在访问之后的返回结果为:

    2、在路由设计时,url地址当中不区分字母的大小写

    如下所示的示例代码:

    const express = require('express');
    var app = express();
    app.get('/ABb',(req,res)=>{
       res.send('成功返回!')
    });
    app.listen(3000,'192.168.155.1');

    此时客户端以get方式访问该网址时,不区分字母大小写。

    3、在做路由处理时,用户输入的url地址当中所有get方式提交的参数及锚点均会被忽略

    如下所示的示例代码:

    const express = require('express');
    var app = express();
    app.get('/a',(req,res)=>{
       res.send('成功返回!')
    });
    app.listen(3000,'192.168.155.1');

    此时客户端访问为http://192.168.155.1:3000/a#?name=qianqian&age=24时,同样与上述这条路由相匹配,执行其内部的回调函数。

    4、express当中所有路由中间件的书写顺序至关重要

    当有客户端访问该服务器时,会根据用户输入的网址与我们的路由设计的代码进行路由匹配,一旦找到一个匹配的路由中间件之后,则执行其内部的回调函数,之后不再与后面代码当中出现的路由中间件进行路由匹配。如下所示的示例代码:

    const express = require('express');
    var app = express();
    app.get('/:username/:method',(req,res)=>{
       console.log(1);
       res.end();
    });
    app.get('/admin/login',(req,res)=>{
        console.log(2);
        res.end();
    })
    app.listen(3000,'192.168.155.1');

    此时当客户端访问http://192.168.155.1:3000/admin/login时,由于先匹配上了第一个路由,执行内部的回调函数,不再匹配第二个路由。

    如果想让其匹配上多条路由,则在上述的可能匹配上的路由的回调函数当中加入参数next,并在回调函数体的最后加上next();即可。示例代码如下所示:

    const express = require('express');
    var app = express();
    app.get('/:username/:method',(req,res,next)=>{
       console.log(1);
       next();
    });
    app.get('/admin/login',(req,res)=>{
        console.log(2);
        res.end();
    })
    app.listen(3000,'192.168.155.1');

    此时当客户端访问http://192.168.155.1:3000/admin/login时,由于先匹配上了第一个路由,执行内部的回调函数,接下去再匹配第二个路由,然后执行其回调函数。

    由于express当中所有路由中间件的书写顺序至关重要,所以我们在设计路由时,一般把具体的路由写在上面,把抽象的路由写在下面。

    5、app.use()是一个特殊的路由中间件

    我们使用app.get()app.post()等路由中间件进行路由设计时,我们都是需要对客户端输入的网址进行精确的路由匹配的(最多只能做到忽略url当中的锚点即get方式提交的参数数据)。但用app.use()来进行路由设计时,我们可以把第一个参数的层级无限扩充下去。示例代码如下所示:

    const express = require('express');
    var app = express();
    app.use('/admin',(req,res)=>{
        res.send('成功匹配!')
    })
    app.listen(3000,'192.168.155.1');

    此时当客户端访问http://192.168.155.1:3000/admin/new/path时,也能匹配上这个路由,从而执行内部的回调函数。

    此时我们可以在回调函数内部使用req.originalUrlreq.baseUrlreq.path来得到用户输入的网址当中的各个部分。示例代码如下所示:

    const express = require('express');
    var app = express();
    app.use('/admin',(req,res)=>{
        console.log(req.originalUrl);
        console.log(req.baseUrl);
        console.log(req.path);
        res.send('成功匹配!')
    })
    app.listen(3000,'192.168.155.1');

    此时当客户端访问http://192.168.155.1:3000/admin/new/path时,结果为:

    当我们使用app.use()这个路由中间件时,如果不写网址或写'/',则相当于与该指定ip与指定端口号下的所有网址进行匹配,因为所有网址都可以看做时'/'的扩展。app.use((req,res)=>{});。我们可以在路由表的最后写上app.use((req,res)=>{res.status(404).send('没有这个页面!');});可以做404页面,当路由表当中所有路由都匹配不上时,则落入该路由项当中。我们可以用res.status(404).send('没有这个页面!');这种方式设置指定的状态码。

    四、express提供静态文件的伺服能力

    类似于Apache之类的传统服务器软件,都默认提供静态服务,有web容器和根目录的概念。而对于Node.js来说,没有web容器和根目录的概念,所以当使用node.js来呈递页面时,需要进行顶层路由设计,来把用户访问的url地址和文件联系在一起。但express提供静态文件的伺服能力。我们可以用app.use(express.static(target));来指定用于提供静态资源服务的文件夹,其中target表示为提供静态资源服务的文件夹的绝对物理地址。
    在主文件1.js的同目录下新建一个public文件夹。示例代码如下所示:

    const express = require('express');
    const path = require('path');
    var target = path.join(__dirname,'./public');
    var app = express();
    app.use(express.static(target));
    app.listen(3000,'192.168.155.1');

    此时我们在public文件夹下新建一个index.html页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <h2>提供静态资源服务文件夹当中的首页页面!</h2>
    </body>
    </html>

    此时public文件夹为提供静态资源服务的文件夹,当用户端访问http://192.168.155.1:3000时,默认进入public文件夹,显示该文件夹当中的index.html页面。

    我们也可以在app.use()方法当中加上第一个参数,如app.use('/static',express.static(target));此时用户需要输入http://192.168.155.1:3000/static时,才会相当于进入public文件夹,显示该文件夹当中的index.html页面。

    我们一般把提供静态资源服务的路由代码写在上面,防止我们在进行路由表设计时,与现有的路由发生冲突。

    五、express与后台模板引擎的配合能力

    这里主要介绍express与后台模板引擎ejs的配合能力。我们将ejs下载到项目文件夹的node_modules文件夹当中,在主文件1.js当中不再需要使用require的方式进行引入。只要写app.set("view engine","ejs");则完成了引包的工作。接下去再在当前目录下新建一个固定文件名为views的文件夹,把渲染的html页面放在其中,后缀名改为.ejs。用res.render("文件名",{数据});
    我们在与主文件1.js的同目录下新建一个views文件夹,里面新建一个index.ejs的文件,内部代码为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <h2>后台模板引擎:<%= a %></h2>
        <ul>
            <% for(var i = 0; i < list.length; i++){ %>
                <li><%= list[i] %></li>
            <% } %>
        </ul>
    </body>
    </html>

    其中主文件1.js的示例代码为:

    const express = require('express');
    var app = express();
    app.set("view engine","ejs");
    app.get('/',(req,res)=>{
        res.render("index",{
            a:'ejs',
            list:['apple','banana','pear','tomato']
        })
    })
    app.listen(3000,'192.168.155.1');

    此时结果为:

    如果我们不想使用views文件夹,我们可以通过 app.set("views","abc");命令更改默认文件夹的名字。

    六、express当中处理get、post的请求参数

    get请求的参数在url当中,在express当中,不再需要使用url模块,直接使用req.query即可得到客户端通过get请求发送的参数对象。示例代码如下所示:

    const express = require('express');
    var app = express();
    app.get('/',(req,res)=>{
       console.log(req.query);
       res.send('成功!');
    });
    app.listen(3000,'192.168.155.1');

    post请求在express当中不能直接获得,需要使用第三方模块包body-parser。通过npm的方式完成模块包的下载之后,常用的代码为const bodyParser = require('body-parser');app.use(bodyParser.urlencoded({extended:false}));,之后即可使用req.body来得到参数对象。
    我们在views文件夹当中写下一个form.ejs表单,示例代码如下所示:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <form action="http://192.168.155.1:3000" method="POST">
            <p>姓名:<input type="text" name="name"></p>
            <p>年龄:<input type="text" name="age"></p>
            <p><input type="submit" value="提交"></p>
        </form>
    </body>
    </html>

    其中主文件1.js的示例代码为:

    const express = require('express'); 
    const bodyParser = require('body-parser');
    var app = express();
    app.set('view engine','ejs');
    app.use(bodyParser.urlencoded({extended:false}));
    app.get('/',(req,res)=>{
       res.render('form');
    });
    app.post('/',(req,res)=>{
        console.log(req.body);
        res.send('表单提交成功!');
    });
    app.listen(3000,'192.168.155.1');

    此时在启动在服务器之后,客户端输入网址http://192.168.155.1:3000时,呈递该表单:

    当完成表单填写,并提交之后,结果为:

    这样就实现了一个post方式表单提交的功能。

    body-parser是一个轻量级的模块包,仅仅适合处理表单内容的提交,但不能处理文件、图片等多媒体文件的提交。如果客户端提交的表单当中包含文件、图片等,还是建议使用formidable模块包进行处理。

  • 相关阅读:
    shiro登录验证原理
    注解 java.lang.annotation.Inherited 介绍
    Spring Boot默认Initializer(1)——ConfigurationWarningsApplicationContextInitializer
    Java的static类
    Spring Boot中的initializers的作用分析
    2. Spring Boot项目启动原理初探
    1.Spring Boot入门及其jar包依赖模型分析
    关于正则式中的 |
    iOS :ViewDidAppear
    Xcode
  • 原文地址:https://www.cnblogs.com/guchengnan/p/10665857.html
Copyright © 2011-2022 走看看