Express

作者: 致自己_cb38 | 来源:发表于2019-06-05 17:45 被阅读0次

    Express框架

    1. 课程介绍

    Ø Express介绍(了解)

    Ø Express安装及使用(掌握)

    Ø Express路由(掌握)

    Ø response响应对象(掌握)

    Ø request请求对象(掌握)

    Ø 中间件(了解)

    1. Express介绍

    Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

    Express 框架核心特性:

    可以设置中间件来响应 HTTP 请求。

    定义了路由表用于执行不同的 HTTP 请求动作。

    (url = 资源) 映射

    可以通过向模板传递参数来动态渲染 HTML 页面。 模板引擎

    1. Express使用

    3.1. 简单使用(了解)

    1、新建一个NodeJs项目文件夹

    2、npm init 初始化项目配置文件(package.json 包描述文件)

    package.json中

    "scripts": {
       "start":"node ./index" //命令
    }
    

    npm start 执行”start”后面的代码。

    3、安装express

    npm install express --save
    

    4、编写一个app.js使用express

    //导入express模块
        var express = require("express");
        //创建一个express应用
        var app = express();
    
        //处理"/"请求
        app.get("/",function(req,res){
             //响应输出“hello world”
             res.send("Hello world");
        });
    
        //启动服务器监听3000端口
        app.listen(3000,function(){
              console.log("express app 启动成功。。。");
        });
    

    5、启动服务器

    node app.js

    6、浏览器访问

    image.png

    3.2. Express-generator(重点)

    为了快速的创建express项目,express团队为使用者提供了项目快速生成工具,express-generator

    为了快速的创建express项目,express团队为使用者提供了项目快速生成工具,express-generator。
    

    1、安装express-generator

    npm i express-generator -g  //全局安装
    

    2、新建一个目录(或者找一个空目录)

    F:\webproject (目录可以新建在任何位置,但最好不要中文路径)
    

    3、通过命令创建express项目

    express -e projecname  (express代表在当前目录下面建立express项目 -e代表使用ejs模版引擎)
    

    express webapp (代表在当前目录下面,新建一个webapp文件夹,然后在建立express项目)

    image.png

    项目结构:

    bin : 执行文件,也是express项目启动文件。

    public:公共的资源,浏览器可以直接访问的资源。(图片,js,css)

    views:服务器端模块文件。

    routes:路由处理器,处理浏览器发出不同url的处理程序。

    /login   function(){
    
    //登录处理程序
    
    }
    

    app.js express应用的主文件,该文件主要用于整合其他第三方模块和配置express的系统参数。

    4、安装依赖包

    通过package.json

    "dependencies": {
      "body-parser": "~1.15.1",
      "cookie-parser": "~1.4.3",
      "debug": "~2.2.0",
      "ejs": "~2.4.1",
      "express": "~4.13.4",
      "morgan": "~1.7.0",
      "serve-favicon": "~2.3.0"
    }
    

    npm i

    image.png

    5、启动express

    node app 需要设置监听端口

    npm start

    node ./bin/www

    image.png
    补充:nodemon:https://stackoverflow.com/questions/49001369/nodemonexpressjs-app-not-starting-clean-exit-waiting-for-changes-before-resta
    image.png

    6、浏览器访问

    image.png

    3.3. Express服务器项目结构说明

         bin: 执行文件,也是express项目启动文件。
    
        public: 公共的资源(nodejs不做处理),浏览器可以直接访问的资源,相当于静态网页的根目录,访问时不需加路径。(图片,js,css)
        http://localhost:3000/test.html
        http://localhost:3000/images/img.jpg
    
        views: 服务器端模块或模板文件。
    
        routes: 路由处理器,处理浏览器发出不同url的处理程序。动态网页的目录
    
        ----------------------------------------------------------------------------------
        app.js 主模块文件,是总路由,分支路由写在routes目录下
        package.json 包管理,依赖包
    
        //引入系统和第三方模块
        var express = require('express');
        var path = require('path');
        var favicon = require('serve-favicon');
        var logger = require('morgan');
        var cookieParser = require('cookie-parser');
        var bodyParser = require('body-parser');
    
        //引入路由
        var index = require('./routes/index');
        var users = require('./routes/users');
        var vipCenter=require("./routes/vip");
    
        //实例化express框架
        var app = express();
    
        // view engine setup
        //设置模板的默认目录
        app.set('views', path.join(__dirname, 'views'));
        //设置ejs为模板引擎
        app.set('view engine', 'ejs');
    
        // uncomment after placing your favicon in /public
        //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
        //中间件
        app.use(logger('dev'));
        app.use(bodyParser.json());
        app.use(bodyParser.urlencoded({ extended: false }));
        app.use(cookieParser());
        //设置静态目录为public
        app.use(express.static(path.join(__dirname, 'public')));
    
        //使用分路由
        app.use('/', index);
        app.use('/users', users);
        app.use("/vip",vipCenter);
    
        // catch 404 and forward to error handler
        //404找不到
        app.use(function(req, res, next) {
          var err = new Error('Not Found');
          err.status = 404;
          next(err);
        });
    
        // error handler
        //错误
        app.use(function(err, req, res, next) {
          // set locals, only providing error in development
          res.locals.message = err.message;
          res.locals.error = req.app.get('env') === 'development' ? err : {};
    
          // render the error page
          res.status(err.status || 500);
          res.render('error');
        });
    
        //导出模块
    module.exports = app;
    
    1. Express路由(重点)

    路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

    路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄(函数)组成,它的结构如下: app.METHOD(path, [callback...], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。

    4.1. 基础用法

    var express = require('express');
    var app = express();
    
    //设置请求路径“/”对应的处理器
    app.get('/', function(req, res) {
      res.send('hello world');
    });
    

    4.2. 路由方法

    路由与HTTP 请求方法(GET、POST)相关联。
    
    为应用“/”路径定义的 GET 和 POST 请求:
    // 处理get请求方式,超链接、浏览器地址栏直接访问
    app.get('/', function (req, res) {
      res.send('处理get请求');
    });
    
    // 处理post请求方式,表单提交
    app.post('/', function (req, res) {
      res.send('处理post请求');
    });
    
    app.all() 是一个特殊的路由方法,没有任何 HTTP 方法与其对应,它的作用是对于一个路径上的所有请求加载中间件。 all相当于既可以处理GET,也可以处理POST。
    
    app.all('/, function (req, res, next) {
      res.send('任意方式的请求');
    });
    

    4.3. Router(重点中的重点)

    express.Router 类可以创建模块化(独立的)、可挂载的路由对象。Router 对象是一个完整的中间件和路由系统,因此常称其为一个 “mini-app”。

    1、新建一个模块vip.js (express项目要求我们放到routes)

    var express = require('express');
    var router = express.Router();
    
    // 定义模块的主页的路由
    router.get('/', function(req, res) {
      res.send('vip首页');
    });
    // 定义模块“/getScore”路径的路由
    router.get('/getScore', function(req, res) {
      res.send('vip积分');
    });
    module.exports = router;
    

    2、app.js 使用

    var vip = require('./vip);
    
    ...
    
    app.use('/vip', vip);  // 路径“/vip”使用vip路由模块,这个行为就是把“vip”模块挂载到“/vip”路径下面。
    
    访问
    
    [http://localhost:3000/vip](http://localhost:3000/vip)/           //vip首页
    
    [http://localhost:3000/vip](http://localhost:3000/vip)/getScore    //vip积分
    
    1. 响应对象(重点)

    响应对象(res)的方法向客户端返回响应,终结请求响应的循环。如果在路由函数中一个方法也不调用,来自客户端的请求会一直挂起。

    5.1. send方法(重点中的重点)

    send(data) 可以返回任意类型数据。
    
    res.send(new Buffer('whoop'));//流
    res.send({ some: 'json' });// json数据
    res.send('<p>some html</p>');//普通文本
    
    //设置状态码,并且返回内容
    res.status(404).send('Sorry, we cannot find that!');
    res.status(500).send({ error: 'something blew up' });
    

    5.2.json方法
    json(data) 返回json对象,一般针对ajax应用。

    res.json(null);
    res.json({ user: 'tobi' });
    
    //设置状态码,并返回json数据
    res.status(500).json({ error: 'message' });
    

    5.3. jsonp方法

    jsonp(data) 返回json对象,一般针对ajax的跨域访问。
    
    res.jsonp(null);
    res.jsonp({ user: 'tobi' });
    
    //设置状态码,并返回json数据
    res.status(500).jsonp({ error: 'message' });
    

    5.4. render视图模板

    ejs模板的使用

    index.ejs模板

    <!DOCTYPE html>
    <html>
      <head>
        <title><%= title %></title>
        <link rel='stylesheet' href='/stylesheets/style.css' />
      </head>
      <body>
        <ul id="mainNav">
           <li><a href="/">首页</a></li>
           <li><a href="/news">新闻中心</a></li>
           <li><a href="/vip">vip会员中心</a></li>
           <li><a href="/users">用户注册</a></li>
        </ul>
        <h1><%= title %></h1>
        <p>Welcome to <%= title %></p>
      </body>
    </html>
    

    index.js 路由

    var express = require('express');
    var router = express.Router();
    
    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });  //将视图和数据合并后发送给客户端
    
    });
    
    module.exports = router;
    

    5.5. download下载

    //下载当前目录下面的xxx.doc文件,并且重命名为yyy.doc。
    router.get('/down', function(req, res, next) {
      res.download("./downTest.doc","express使用说明.doc")
    });
    

    5.6. redirect重定向

    重定向到从指定的URL路径(浏览器地址变为设置的地址)

     router.get('/it', function(req, res, next) {
       res.redirect("http://www.baidu.cn");
    });
    

    5.7. 404报错页面制作

    image.png
    router.get('/err', function(req, res, next) {
      //res.status(404).send("出错了:文件没有找到!");
      res.status(404).render("error",{message:"很抱歉,您查看的宝贝不存在,可能已下架或者被转移。"});
    });
    
    error.ejs
    <h1><%= message %></h1>
    <p><img src="./images/err.png" /></p>
    

    5.8. 完整api

    1. res.app:同req.app一样

    2. res.append():追加指定HTTP头

    3. res.set()在res.append()后将重置之前设置的头

    4. res.cookie(name,value [,option]):设置Cookie

    opition: domain / expires / httpOnly / maxAge / path / secure / signed

    1. res.clearCookie():清除Cookie
    npm install cookie
    
    npm install cookie
    var cookie=require("cookie");
    res.cookie("username",username);  // 设置cookie
    req.cookies.名称                // 取值
    res.clearCookie(‘名称’);       // 清除指定名称的Cookie
    手动清除cookie,设置》高级》清除浏览数据
    router.get("/checkLogin",function(req,res,next){
        var username=req.cookies.username;
        if(username) {
            res.send(true);
        }
        else{
            res.send(false);
        }
    });
    
    image.png
    1. res.download():传送指定路径的文件

    2. res.get():返回指定的HTTP头

    3. res.json():传送JSON响应

    4. res.jsonp():传送JSONP响应

    5. res.location():只设置响应的Location HTTP头,不设置状态码或者close response

    6. res.redirect():设置响应的Location HTTP头,并且设置状态码302

    7. res.send():传送HTTP响应

    8. res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type

    9. res.set():设置HTTP头,传入object可以一次设置多个头

    10. res.status():设置HTTP状态码

    11. res.type():设置Content-Type的MIME类型

    12. 请求对象(重点)

    req(request)对象包含了数一次请求中的所有据(http头信息、请求参数...)

    6.1. 获取浏览器地址栏中的参数(重点中的重点)

    语法: req.query.参数名;

    比如:http://localhost:3000/user?name=007

          req.query.name;
    

    搜索功能

    search.html?keywords=笔记本电脑&catetype=it数码
    
    router.get('/search.html', function(req, res, next) {
      var keywords=req.query.keywords;
      var catetype=req.query.catetype;
      res.json({"关键词":keywords,"类别":catetype});
    });
    

    6.2. 获取表单提交的值(重点中的重点)

    Post提交 req.body.参数名

    Get提交 req.query.参数名;

    login.html   public静态文件
        <form action="/loginPost" method="post">
            <p>用户账号 <input type="text" name="username" /></p>
            <p>登录密码 <input type="password" name="pwd" /></p>
            <p><input type="submit" value="Post登录" /> </p>
        </form>
        <hr/>
        <form action="/loginGet" method="get">
            <p>用户账号 <input type="text" name="username" /></p>
            <p>登录密码 <input type="password" name="pwd" /></p>
            <p><input type="submit" value="Get登录" /> </p>
        </form>
       路由文件
    router.get('/loginGet', function(req, res, next) {
      var username=req.query.username;
      var pwd=req.query.pwd;
      res.json({"账号":username,"密码":pwd});
    });
    
    router.post('/loginPost', function(req, res, next) {
      var username=req.body.username;
      var pwd=req.body.pwd;
      res.json({"账号":username,"密码":pwd});
    });
    

    6.3. 获取路由中的参数parameters

    京东的产品地址:https://item.jd.com/5268701.html

      /product/9999
    
      router.get("/product/:id",function(req,res){
        var productID=req.params.id;
        res.send("产品的编号是:"+productID);
    });
    

    parameter [pəˈræmɪtɚ] params [pəˈræms]

    伪静态: 看起来是一个静态文件,但其实是动态的。好处可以方便搜索引擎收录

    6.4. 获取ip地址

    router.get('/home', function(req, res, next) {
      res.send("<h1>我是首页homepage!!!</h1><p>你的ip地址是:"+req.hostname+"_"+req.ip+"</p>");
    });
    

    6.5. 完整api

    1. req.app:当callback为外部文件时,用req.app访问express的实例

    2. req.baseUrl:获取路由当前安装的URL路径

    3. req.body / req.cookies:获得「请求主体」/ Cookies

    4. req.fresh / req.stale:判断请求是否还「新鲜」

    5. req.hostname / req.ip:获取主机名和IP地址

    6. req.originalUrl:获取原始请求URL

    7. req.params:获取路由的parameters

    8. req.path:获取请求路径

    9. req.protocol:获取协议类型

    10. req.query:获取URL的查询参数串

    11. req.route:获取当前匹配的路由

    12. req.subdomains:获取子域名

    13. req.accpets():检查请求的Accept头的请求类型

    14. req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages

    15. req.get():获取指定的HTTP请求头

    16. req.is():判断请求头Content-Type的MIME类型

    1. 中间件(了解)

    Express 是一个自身功能极简,完全是由路由中间件构成一个的 web 开发框架:从本质上来说,一个 Express 应用就是在调用各种中间件。

    image.png

    7.1. 中间件到底是什么

    中间件(Middleware)本质就是一个函数,它可以访问请求对象(request object), 响应对象(response object), 和 web 应用中处于请求-响应循环流程中的中间件,一般被命名为 next 的变量。(next 尾函数,执行下一个任务)

    中间件的功能包括:

      执行任何代码。
    
      修改请求和响应对象。
    
      终结请求-响应循环。
    
      调用堆栈中的下一个中间件。
    

    如果当前中间件没有终结请求-响应循环,则必须调用 next() 方法将控制权交给下一个中间件,否则请求就会挂起。

    7.2. 应用级中间件

    应用级中间件绑定到 app 对象 使用 app.use() 和 app.METHOD(), 其中, METHOD 是需要处理的 HTTP 请求的方法,例如 GET, PUT, POST 等等,全部小写。

    //最简单的中间件
    
    app.js
    var express = require('express');
    var app = express();
    …………………………. ………………………….
    
    /*
     * 中间件:
     *  1. 中间件是一个函数
     *  2. 中间件可以访问请求对象和响应对象
     *  3. 可以阻止请求继续执行,如果不阻止,可以调用尾函数 next()
     *
     * 尾函数next:
     *  1. 在一个中间件中执行尾函数,就可以调用下一个中间件
     *  2. 如果不用调用尾函数,就阻止执行
     *  3. 在尾函数后面的代码会执行,并且是在尾函数调起的下一个中间件结束后才执行
     */
    
     app.use(function(req,res,next){
     console.log('111');
     next();
     console.log('222');
     });
    
     app.use(function(req,res,next){
     console.log('333');
     next();
     console.log('444');
     });
    
    …………………………. ………………………….
    module.exports = app;
    

    7.3. 内置中间件

    Express中只为我们提供了唯一一个中间件,其他的中间件需要安装。


    image.png
    image.png

    下面的例子使用了 express.static中间件,其中的 options 对象经过了精心的设计。

    var options = {
      dotfiles: 'ignore',
      etag: false,
      extensions: ['htm', 'html'],
      index: false,
      maxAge: '1d',
      redirect: false,
      setHeaders: function (res, path, stat) {
        res.set('x-timestamp', Date.now());
      }}
    
    app.use(express.static('public', options));
    每个应用可有多个静态目录。
    app.use(express.static('public'));
    app.use(express.static('uploads'));
    app.use(express.static('files'));
    
    app.use(logger('dev'));  //控制台日志显示的中间件
    app.use(express.static(path.join(__dirname, 'public')));   //静态资源目录的中间件
    

    7.4. 第三方中间件

    通过使用第三方中间件从而为 Express 应用增加更多功能。

    安装所需功能的 node 模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。

    Multer 翻译文档https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md

    文件上传中间件的使用

    fileUpload.html 静态页面

    fileUpload.html 静态页面
        <form action="/upload" method="post" enctype="multipart/form-data">
            <h2>图片上传</h2>
            <input type="file" name="imgUpload">
            <input type="submit" value="上传">
        </form>
    

    index.js 路由

    /*
     * npm i multer --save
     *
     前端准备工作:
     1、需要一个表单,表单里面必须有一个文件域
     2、必须给form表单指定enctype="multipart/form-data" 属性。
     3、提交按钮类型为submit。
    
     后端:接收请求
     1:前端请求表单页面http://127.0.0.1/upload/
     2:渲染模板,不需加载额外的数据。
    
     教程:
     http://blog.csdn.net/CatieCarter/article/details/77841208
     https://github.com/expressjs/multer
     */
    
    //引入文件模块
    var fs = require("fs");
    
    //引入上传中间件模块
    var multer  = require('multer');
    
    //初始化上传目录,自定义本地保存的路径
    //var upload = multer({ dest: './files/' }); //使用storage时不需要单独制定目录,storage中有目录设置
    var uploadFolder='./public/files/'; //放入静态资源目录才能正常显示
    
    // 通过storage的 filename 属性定制上传文件名称
    var storage = multer.diskStorage({
      destination: function (req, file, cb) {
        cb(null, uploadFolder);    // 保存的路径,备注:需要自己创建如果不存在会报错
      },
      filename: function (req, file, cb) {
        //将保存文件名设置为 前缀+时间戳+文件扩展名
        var extName=file.originalname.substring(file.originalname.lastIndexOf(".")); //.jpg
        cb(null, file.fieldname + '_' + new Date().getTime() + extName);
      }
    });
    
    // 通过 storage 选项来对 上传行为 进行定制化
    var upload = multer({ storage: storage });
    
    //文件上传的路由,upload.single("imgUpload")指定单个文件上传,上传框的名称为imgUpload
    router.post('/upload',upload.single("imgUpload"), function(req, res, next) {
      var fileInfo = req.file; //multer会将文件的信息写到 req.file上
      console.log('文件类型:', fileInfo.mimetype);
      console.log('原始文件名:', fileInfo.originalname);
      console.log('文件大小:', fileInfo.size);
      console.log('文件保存路径:', fileInfo.path);
    
      //渲染图片显示的模板,直接获取文件存放的地址,显示时不需要public目录
      var filepath=fileInfo.path.toString().replace("public","");
      res.render("imgFileList.ejs",{imgShow: filepath});
    
      //直接显示出来
      res.set({"Content-Type":"text/html"});
      res.send("<img src='"+fileInfo.path.toString().replace("public","")+"' />");
    });
    
    imgFileList.ejs  图片显示模板
      <body>
        <h1>图片上传展示</h1>
        <p><img src="<%= imgShow%>" /></p>
      </body>
    
    image.png
    1. 课程总结

    8.1. 重点

    1. 安装 express

    2. express的路由编写

    3. 请求对象

    4. 响应对象

    8.2. 难点

    1. 路由编写

    2. 中间件

    8.3. 如何掌握?

    1. 此技能通过使用升级。

    2. 将常见的用法截图保存到文件夹中,时常回顾。

    8.4. 排错技巧(技巧)

    1. console.log()方法。

    2. 作业

    作业难度:☆☆☆

    1、在自己的电脑上安装exress框架

    2、如何获取GET和POST方式传值,分别使用什么方法。

    3、编写路由实现一个简易的企业网站基本结构,根据不同链接路径响应不同的内容。

       首页 | 新闻中心 | 产品展示 | 客户留言 | 关于我们 | 联系我们 | 官方商城
    
    1. 面试题
    1. 网络服务器的工作原理
    1. 扩展知识或课外阅读推荐(可选)

    11.1. 扩展知识

    使用 express-generator 创建的基本框架中各个目录的作用,以及静态目录

    【补充】 cookie

    由于HTTP是无状态协议,无法识别两次请求之间的关系,为了识别用户身份使用cookie技术。cookie技术是一向由服务器端设置数据,存储在客户端浏览器缓存中的一项技术。

    只要服务器向浏览器设置了cookie,每一次浏览器发起请求时,都会自动携带这些cookie数据去访问服务器。服务器可以接收到数据并识别用户身份。

    //设置新的cookie
        res.cookie('名称','值');
        
        //修改cookie
        res.cookie('名称','新的值');
        
        //删除cookie
        res.clearCookie('名称');
        
        //获取查询使用cookie
        req.cookies.名称;
    
    req.cookies.名称;
    

    npm i --save nodemon
    nodemon appname

    相关文章

      网友评论

          本文标题:Express

          本文链接:https://www.haomeiwen.com/subject/vlurxctx.html