Fork me on GitHub

express入门

https://www.cnblogs.com/SamWeb/p/6711351.html

 

 Express 是node 第三方框架,大家都知道,框架的意义就在于能大大简化程序地开发。那么我们就看一下Express是怎么简化node程序开发的。

  1,用Express写一个hello world 程序,我们来体验一下Express 开发。

  新建文件夹express,npm init -y 快速创建package.json, 再新建一个server.js 用于项目启动。由于express 是第三方框架,我们要先安装它,npm install express -S,  server.js 代码如下:

复制代码
let express = require("express");
let http = require("http");

let app = express();
app.use(function(req,res){
    res.writeHead("200",{'content-type':'text/plain'})
    res.end("Hello World")
})

http.createServer(app).listen(8080)
复制代码

  现在在当前文件夹中,调用cmd 命令窗口,输入node server 开启服务器,浏览器中输入localhost:8080 可以看到Hello World. 现在我们再把原生node 代码拿过来(如下),看一下它们的区别。

复制代码
let http = require("http");

// 创建请求处理函数
let app = function(req,res) {
    res.writeHead("200",{'content-type':'text/plain'})
    res.end("Hello World")
}

http.createServer(app).listen(8080)
复制代码

  原生node 程序和Express 程序最主要的区别的就是请求处理函数,原生node是直接创建一个函数来处理请求,所有请求和响应操作都放到这一个函数里。Express 则是调用 express()返回一个请求处理函数, 然后调用该函数的use方法来处理请求。

  这里可以简单看一下express 的源码,看一下app请求处理函数, 当require(‘express’) 时,node 会寻找node_modules下面的express, 它是一个文件夹,就会寻找它下面的index.js 文件,这是node CommonJS 规范规定的。index.js 文件如下:

module.exports = require('./lib/express');

  我们再看一下lib 文件夹下的express.js 文件(如下),可以看到它暴露出createApplication函数, 我们定义的express 变量就是指向这个函数,

exports = module.exports = createApplication

  看一下这个函数(如下),它返回app. 所以当程序中执行express() 的时候,它返回了app, app 就是function(req,res,next) 函数, 就是我们的请求处理函数,mixin(app,proto,false), 就是给app

增加一些方法,如这里的use 方法。

复制代码
function createApplication() {
  var app = function(req, res, next) {
    app.handle(req, res, next);
  };

  mixin(app, EventEmitter.prototype, false);
  mixin(app, proto, false);

  // expose the prototype that will get set on requests
  app.request = Object.create(req, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  // expose the prototype that will get set on responses
  app.response = Object.create(res, {
    app: { configurable: true, enumerable: true, writable: true, value: app }
  })

  app.init();
  return app;
}
复制代码

  到底app 有哪些方法,我们不妨把它打印出来。在文件夹中随便建一个js 文件,如 applog.js 看一下,看完之后就可以删除。在applog.js 中输入如下代码

let express = require("express");
let app = express();
console.log(app)

  在命令行中输入node applog ,可以看到{ [Function: app] .... }等,可以看到它是一个函数, 还有use, set, post ,listen等方法。

  其实http.createServer(app).listen(8080)可以简写为app.listen(8080),因此我们的代码还可以更为简单,

复制代码
let express = require("express");
let app = express();

app.use(function(request, response) {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Hello, world!");
});
app.listen(8080);
复制代码

  2, 中间件

   调用express()返回app 请求处理函数,然后调用app.use 来处理请求,这么写到到底有什么好处? 最主要的就是我们可以把请求处理,放到不同的函数进行,从而避免了在原生node 中只有一个函数进行处理的问题。把所有的处理逻辑放到一个函数,不利于代码的维护和扩展。

  现在我们想要在响应之前输出请求日志,用Express,我们就可以直接在程序中填加app.use(), 而不用管以前的代码,而且原生node, 我们还是要在请求处理函数中填加。Express 代码如下:

复制代码
var express = require("express");var app = express();

//  记录请求日志
app.use(function(request, response, next) {
    console.log("In comes a " + request.method + " to " + request.url);
   next();
});
// 对请求做出响应
app.use(function(request, response) {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Hello, world!");
});
app.listen(8080);
复制代码

  这里,我们调用两个函数对http 请求进行处理,一个记录日志,一个负责响应,这就是Express 的中间件思想,不是把http请求放到一个大的函数中进行处理,而是把请求进行分解,放到一堆函数中进行处理,Express 则按照函数的书写顺序从上到下依次执行。 并且一个函数只做一件事件,这有利于模块化,代码的复用,更重要的是可以引用第三方模块。那么中间件是什么? 它就是这一堆函数中的每一个函数,就是我们app.use 中的函数。

  现在来体验一下第三方中间件

  上面我们写了记录请求日志的函数,其实我们不用写,早就有第三方模块:morgan。我们只要先安装,再引用就可以了,npm install morgan -S 安装,然后在文件中替换掉我们自己的函数

复制代码
var express = require("express");
var app = express();

let logger = require("morgan");  // 引入morgan
app.use(logger("short"))   // 替换掉自己的函数

// 对请求做出响应
app.use(function(request, response) {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Hello, world!");
});
app.listen(8080);
复制代码

  我们再用一下Express 唯一的内置的中间件static 中间件,它提供静态文件服务,例如浏览器请求图片。我们在express 文件夹下新建public文件夹,用于存放静态资源,我们放一张图片(如:flower.png)在里面. static 中间件使用也非常简单,它只接受一个参数,就是我们静态文件放置的目录。我们修改代码看一下:

复制代码
let express = require('express')
let app = express(); 
let path = require('path');

let publicPath = path.resolve(__dirname,'public') // 获取静态文件所在的目录
app.use(express.static(publicPath));  // express static 中间件。

app.use(function(req,res){
    res.writeHead("200",{'content-type':'text/plain'})
    res.end("no static file")
})
app.listen(8080)
复制代码

  当我们在浏览器中输入localhost:8080/flower.png的时候,网页显示一张图片。但当我们输入localhost:8080  时候,no static file. 当有静态文件服务的时候,如果我们请求的静态文件正好和服务器上的资源相匹配,它就会返回静态资源,程序也不会继续执行。 如果没有相匹配的静态资源,程序就会继续执行,返回 no static file.

  3, 路由

  Express提供了强大的路由,我们可以很轻松地实现路由。路由就是不同的url 对应不同内容,例如用户点击about , 我们就要返回 about 页面,用户点击home,我们就要返回首页。Express 路由是app.method(path, function) 来实现的. method就是指的get, post 请求,path 指的就是/about, 后面的函数就是对这个请求的处理。如用户点击about, 服务器该怎么返回呢? 它是一个get 请求,请求的是about, 我们要返回about, 就可以这么写,app.get('/about', function(req,res){res.end("about")}). 再写几个路由加深一下理解。

复制代码
let express = require('express')
let app = express(); 

// 首页路由
app.get("/", function(request, response) {
    response.end("Welcome to my homepage!");
});
// about 路由
app.get("/about", function(request, response) {
    response.end("Welcome to the about page!");
});
// weather 路由
app.get("/weather", function(request, response) {
    response.end("The current weather is NICE.");
});
// 404 页面
app.use(function(request, response) {
    response.statusCode = 404;
    response.end("404!");
});
app.listen(8080)
复制代码

  我们在浏览器中输入localhost:8080/about, 就看到 Welcome to the about page。

  4, express 扩展了 req 和res请求和响应对象,如req.ip 就可以获取请求的ip 地址, res.send()向浏览器发送任意信息, 这比较简单,就不试验了。

  5. 模版引擎

  Express增加了对许多模板引擎的支持,如pug(jade), ejs等,可以动态输出html, 这是原生node所不具有的。我们使用一下ejs,  使用模版引擎有三个步骤,首先是安装,其次是注册,最后是配置。

  安装很简单 npm install ejs -S; 注册是对express 不支的模版如handlebars, 由于Express 原生支持ejs, 所以不需要注册;配置,就是告诉Express要使用哪个模版引擎,模版文件放在什么地方,以便Express在渲染的时候知道从哪里去寻找模版。

  这时在express 文件夹中新建views文件夹,用于放置模版文件, 在views文件夹中新建一个模版文件,如index.ejs

复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello, world!</title>
</head>
<body>
  <%= message %>
</body>
</html>
复制代码

  在server.js中配置模版引擎

app.set("view engine",'ejs');  // 设置 view engine, 使用ejs模版引擎
app.set("views", path.resolve(__dirname,'views'))  // 设置views,模版放置的地方 

  动态渲染模版,输出html。 这要调用res.render()方法,render 方法,接受一个参数就是我们要渲染的模版的名称,还有一个可选的参数,就是向模版中输入的数据 来替换模版中的变量。

调用render方法的时候,express 就向views 文件夹中寻找对应的模版,这也是我们 app.set("views",...) 的原因。

app.get('/', function(req,res){
    res.render('index',{
    message:"this is a ejs view"    
  }) })

  完成的server.js 如下,在浏览器中输入localhost:8080, 就看到 this is a ejs view。

复制代码
let express = require('express')
let path =require('path');

let app = express(); 

// 设置模版引擎
app.set("view engine",'ejs');  
app.set("views", path.resolve(__dirname,'views'))  

// render 渲染模版
app.get('/', function(req,res){
    res.render('index',{
        message: "this is a ejs view"
    })
})
app.listen(8080)
复制代码

  Express 的基本知识就差不多了,通过中间件,路由和模版引擎,同时它还扩展了req,res对象的属性和方法,来简化node 开发。

  我们再通过一个留言本实例来加深Express 的认识

  1, 首先npm init -y 快速创建一个package.json 文件,然后安装所需要的依赖, npm install express morgan body-parser ejs --save。

  2, 新建server.js文件来创建一个服务器,同时新建一个views文件夹存放各种视图文件,这时主要是.ejs 文件。

  server.js 文件如下:

复制代码
// 引入各种模块依赖
const express = require('express');
const logger = require('morgan');
const bodyParser = require('body-parser');
const path = require('path');

// 利用express 创建应用
const app = express();

// 设置模版引擎为ejs
app.set('views', path.join(__dirname, 'views'));
app.set('view engine','ejs');

// 创建一个数组对象,保存用户通过表单上传的内容
var entries = [];

// app.locals,它是一个对象,提供整个app应用所需要的数据,这时属性entries就可以用在模版中
app.locals.entries = entries;

// 使用morgan 中间件记录请求日志
app.use(logger('dev'))

// 利用body-parser 中间件获取用户上传的数据,通过这个中间件,用户上传的数据都会
// 附在req.body的属性上。
app.use(bodyParser.urlencoded({extended: false}))

//路由的设置
app.get('/', (req,res) => {
    res.render('index');
})
app.get('/new-entry', (req,res) => {
    res.render('new-entry');
})

app.post('/new-entry', (req,res) => {
    if(!req.body.title || !req.body.body) {
        res.status(400).send('Entris have a title and body')
        return;
    }
    entries.push({
        title:req.body.title,
        content: req.body.body,
        published: new Date()
    })
    res.redirect('/')
})

// 当用户访问页面,我们的路由都不匹配时,提供回退404页面
app.use((req,res) => {
    res.status(404).render('404')
})

// 监听3000端口,启动服务
app.listen(3000, () => {
    console.log('server started on port 3000')
})
复制代码

  这时需要提供几个页面,index.ejs, new-entries.ejs, 404.ejs, 由于几个页面都有共同的footer和header, 所以我们可以把header 和footer 单独提取出来,形成header.ejs 和footer.ejs,其它页面直接引进就可以了。

  header.ejs

复制代码
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>留言板</title>
        <!--引入bootstrap 提供简单的样式-->
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    </head>
    <body class="container">
        <h1>
            Express 留言板
            <a href="/new-entry" class="btn btn-primary pull-right">
            写一个留言
            </a>
        </h1>
复制代码

  footer.ejs

</body>
</html>

  index.ejs 页面主要显示我们留言的内容,而我们所有的留言都存在的entries数组中,所以要用ejs中的循环对entries 进行遍历,对内容进行输出。由于第一次进入页面,我们并没有任何留言,所以要对entries 进行判断,如果没有内容,要让用户添加留言

复制代码
<!--引入header-->
<% include header %>

<!--对entries进行判断-->
<% if (entries.length) { %>
    <!--有内容,进行循环遍历,显示内容-->
    <% entries.forEach(function(entry) { %>
        <div class="panel panel-default">
            <div class="panel-heading">
                <div class="text-muted pull-right">
                    <%= entry.published %>
                </div>
                <%= entry.title %>
            </div>
            <div class="panel-body">
                <%= entry.content %>
            </div>
        </div>
    <% }) %>
    <!--没有内容,提示用户添加留言-->
<% } else { %>
    没有留言内容! <a href="/new-entry">添加一个留言</a>
<% } %>

<!--引入footer-->
<% include footer %>
复制代码

  所以当第一次进入页面时显示以下内容

  当用户点击添加一个留言, 我们要跳转到添加留言的页面,就是/new-entry页面,这时添加new-entry页面,它就是一个form 表单

复制代码
<% include header %>

<h2>书写一个留言</h2>
<form method="post" role="form">
    <div class="form-group">
        <label for="title">标题</label>
        <input type="text" class="form-control" id="title"
        name="title" placeholder="标题" required>
    </div>
    <div class="form-group">
        <label for="content">内容</label>
        <textarea class="form-control" id="body" name="body"
        placeholder="内容" rows="3" required></textarea>
    </div>
    <div class="form-group">
        <input type="submit" value="提交留交" class="btn btn-primary">
    </div>
</form>

<% include footer %>
复制代码

  当提交订单的时候,我们并没有给form 表单添加action, 表单内容提交到什么地方? 原来表单中没有指定action时,它会提交到当前页面/new-entry, 正好对应server.js中的app.post(‘/new-entry’), 所以当提交订单时,服务端会收到我们传过去的内容。

  页面内容展示如下:

  最后提供一个404.ejs页面

<% include header %>
<h2>404! Page not found.</h2>
<% include footer %>

  好了,在命令行中输入node server.js 开启服务器,然后在浏览器中输入localhost:3000 体验一下。

posted @ 2018-10-20 14:14  森海轮回  阅读(341)  评论(0编辑  收藏  举报