目錄
前面的話
概述
#入門實例
生成器
HTTP模块
中间件
托管静态资源
常用中间件
路由
路由器实例
响应方法
请求方法
app方法
HTTPS
模板引擎
数据库
上传文件
开发实例
首頁 web前端 js教程 express框架入門學習知識點總結

express框架入門學習知識點總結

Jul 17, 2017 pm 03:05 PM
express 框架

前面的話

  Express是一個簡潔、靈活的 node.js Web 應用開發框架, 它提供一系列強大的特性,幫助開發者創建各種 Web 和行動裝置應用。本文將詳細介紹express架構

 

概述

  官網對Express的描述,它是一個基於Node.js 平台,快速、開放、極簡的web 開發框架。優點是易上手、高效能、擴充性強

  1、易上手:nodejs最初就是為了開發高效能web伺服器而被設計出來的,然而相對底層的API會讓不少新手望而卻步。 express對web開發相關的模組進行了適度的封裝,屏蔽了大量複雜繁瑣的技術細節,讓開發者只需要專注於業務邏輯的開發,極大的降低了入門和學習的成本

2.高效能:Express僅在web應用相關的nodejs模組上進行了適度的封裝和擴展,較大程度避免了過度封裝導致的性能損耗

  3、擴展性強:基於中間件的開發模式,使得express應用的擴充功能、模組分割非常簡單,既靈活,擴充性又強

【安裝】

  安裝express前,先安裝nodejs,接下來為應用程式創建一個目錄,然後進入此目錄並將其作為當前工作目錄

$ mkdir myapp
$ cd myapp
登入後複製

  透過npm init 命令為應用建立一個package.json 檔案

#
$ npm init
登入後複製

  此指令要求輸入幾個參數,例如套用的名稱和版本。 直接按下「回車」鍵接受預設設定即可,以下這個除外:

entry point: (index.js)
登入後複製

#  鍵入 app.js 或希望的名稱,這是目前應用的入口檔案。如果希望採用預設的index.js 檔案名,只需按下「回車」鍵即可

  接下來安裝Express 並將其儲存到依賴清單中:

$ npm install express --save
登入後複製

  如果只是暫時安裝Express,不想將它加入到依賴清單中,只需略去--save 參數即可:

$ npm install express
登入後複製

 

#入門實例

  在專案根目錄下,新建一個啟動文件,假定叫做index.js,新建一個public資料夾,並在public目錄下,新建index.html

var express = require('express');var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);
登入後複製

#  運行index.js後,訪問http://localhost:8080,它會在瀏覽器中開啟public目錄的index.html檔案

  當然,也可以在index. js之中,產生動態網頁

// index.jsvar express = require('express');var app = express();
app.get('/', function (req, res) {
  res.send('Hello world!');
});
app.listen(3000);
登入後複製

  執行index.js檔案後,會在本機的3000埠啟動一個網站,網頁顯示Hello World

#  啟動腳本index.js的app.get方法,用於指定不同的存取路徑所對應的回呼函數,這稱為「路由」(routing)。上面程式碼只指定了根目錄的回呼函數,因此只有一個路由記錄。實際應用中,可能有多個路由記錄

var express = require('express');var app = express();

app.get('/', function (req, res) {
  res.send('Hello world!');
});
app.get('/customer', function(req, res){
  res.send('customer page');
});
app.get('/admin', function(req, res){
  res.send('admin page');
});

app.listen(3000);
登入後複製

  這時,最好就把路由放到一個單獨的檔案中,例如新建一個routes子目錄

#
// routes/index.jsmodule.exports = function (app) {
  app.get('/', function (req, res) {
    res.send('Hello world');
  });
  app.get('/customer', function(req, res){
    res.send('customer page');
  });
  app.get('/admin', function(req, res){
    res.send('admin page');
  });
};
登入後複製

  然後,原來的index.js就變成下面這樣

// index.jsvar express = require('express');var app = express();var routes = require('./routes')(app);
app.listen(3000);
登入後複製

 

路由

         当用get请求访问一个网址的时候,做什么事情:

    app.get("网址",function(req,res){2        3    });       

        当用post访问一个网址的时候,做什么事情:

    app.post("网址",function(req,res){2        3    });

       如果想处理这个网址的任何method的请求,那么写all

    app.all("/",function(){2        3    });

       这里的网址,不分大小写,也就是说,你路由是

    app.get("/AAb",function(req,res){2        res.send("你好");3    });

        中间件

        如果我的的get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会往下匹配了。

        如果想往下匹配的话,那么需要写next() 


    app.get("/",function(req,res,next){2        console.log("1");3        next();4    });5    6    app.get("/",function(req,res){7        console.log("2");8    });


       路由get、post这些东西,就是中间件,中间件讲究顺序,匹配上第一个之后,就不会往后匹配了。next函数才能够继续往后匹配。      

       app.use()也是一个中间件。与get、post不同的是,他的网址不是精确匹配的。而是能够有小文件夹拓展的。

       比如网址:  http://127.0.0.1:3000/admin/aa/bb/cc/dd


    app.use("/admin",function(req,res){
        res.write(req.originalUrl + "\n");   //    /admin/aa/bb/cc/dd3        res.write(req.baseUrl + "\n");  //   /admin4        res.write(req.path + "\n");   //    /aa/bb/cc/dd5        res.end("你好");6    });


      ● 大多数情况下,渲染内容用res.render(),将会根据views中的模板文件进行渲染。如果不想使用views文件夹,想自己设置文件夹名字,那么app.set("views","aaaa");

      ● 如果想写一个快速测试页,当然可以使用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');

生成器

  通过应用生成器工具 express 可以快速创建一个应用的骨架

  [注意]一定要使用全局模式安装express-generator,否则无法使用express命令

$ npm install express-generator -g
登入後複製

  -h 选项可以列出所有可用的命令行选项:

$ express -h
  Usage: express [options] [dir]
  Options:-h, --help          output usage information-V, --version       output the version number-e, --ejs           add ejs engine support (defaults to jade)--hbs           add handlebars engine support-H, --hogan         add hogan.js engine support-c, --css <engine>  add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)--git           add .gitignore-f, --force         force on non-empty directory
登入後複製

  例如,下面的示例就是在当前工作目录下创建一个命名为 myapp 的应用

$ express myapp

   create : myapp
   create : myapp/package.json
   create : myapp/app.js
   create : myapp/public
   create : myapp/public/javascripts
   create : myapp/public/images
   create : myapp/routes
   create : myapp/routes/index.js
   create : myapp/routes/users.js
   create : myapp/public/stylesheets
   create : myapp/public/stylesheets/style.css
   create : myapp/views
   create : myapp/views/index.jade
   create : myapp/views/layout.jade
   create : myapp/views/error.jade
   create : myapp/bin
   create : myapp/bin/www
登入後複製

  然后安装所有依赖包:

$ cd myapp 
$ npm instal
登入後複製

  启动这个应用(MacOS 或 Linux 平台):

$ DEBUG=myapp npm start
登入後複製

  Windows 平台使用如下命令:

> set DEBUG=myapp & npm start
登入後複製

  然后在浏览器中打开 http://localhost:3000/ 网址就可以看到这个应用了。i

  通过 Express 应用生成器创建的应用一般都有如下目录结构:

.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.jade
    ├── index.jade
    └── layout.jade7 directories, 9 files
登入後複製

 

HTTP模块

  Express框架建立在node.js内置的http模块上。http模块生成服务器的原始代码如下

var http = require("http");var app = http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.end("Hello world!");
});

app.listen(3000, "localhost");
登入後複製

  上面代码的关键是http模块的createServer方法,表示生成一个HTTP服务器实例。该方法接受一个回调函数,该回调函数的参数,分别为代表HTTP请求和HTTP回应的request对象和response对象。

  Express框架的核心是对http模块的再包装。上面的代码用Express改写如下

var express = require('express');var app = express();

app.get('/', function (req, res) {
  res.send('Hello world!');
});

app.listen(3000);
登入後複製

  比较两段代码,可以看到它们非常接近。原来是用http.createServer方法新建一个app实例,现在则是用Express的构造方法,生成一个Epress实例。两者的回调函数都是相同的。Express框架等于在http模块之上,加了一个中间层

 

中间件

【概述】

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

  简单说,中间件(middleware)就是处理HTTP请求的函数。它最大的特点就是,一个中间件处理完,再传递给下一个中间件。App实例在运行过程中,会调用一系列的中间件

  每个中间件可以从App实例,接收三个参数,依次为request对象(代表HTTP请求)、response对象(代表HTTP回应),next回调函数(代表下一个中间件)。每个中间件都可以对HTTP请求(request对象)进行加工,并且决定是否调用next方法,将request对象再传给下一个中间件

  中间件的功能包括:1、执行任何代码;2、修改请求和响应对象;3、终结请求-响应循环;4、调用堆栈中的下一个中间件

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

  一个不进行任何操作、只传递request对象的中间件,就是下面这样

function uselessMiddleware(req, res, next) {
  next();
}
登入後複製

  上面代码的next就是下一个中间件。如果它带有参数,则代表抛出一个错误,参数为错误文本

function uselessMiddleware(req, res, next) {
  next('出错了!');
}
登入後複製

  抛出错误以后,后面的中间件将不再执行,直到发现一个错误处理函数为止

【分类】

  Express 应用可使用如下几种中间件:1、应用级中间件;2、路由级中间件;3、错误处理中间件;4、内置中间件;5、第三方中间件

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

  2、路由级中间件绑定的对象为 express.Router()

  3、错误处理中间件和其他中间件定义类似,只是要使用 4 个参数,而不是 3 个,其签名如下: (err, req, res, next)

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
登入後複製

  4、express.static 是 Express 唯一内置的中间件。它基于 serve-static,负责在 Express 应用中提托管静态资源

  5、通过使用第三方中间件从而为 Express 应用增加更多功能。安装所需功能的 node 模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。下面的例子安装并加载了一个解析 cookie 的中间件: cookie-parser

$ npm install cookie-parser
登入後複製
登入後複製
var express = require('express');var app = express();var cookieParser = require('cookie-parser');// 加载用于解析 cookie 的中间件app.use(cookieParser());
登入後複製

【use方法】

  use是express注册中间件的方法,它返回一个函数。下面是一个连续调用两个中间件的例子

var express = require("express");var http = require("http");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!\n");
});

http.createServer(app).listen(1337);
登入後複製

  上面代码使用app.use方法,注册了两个中间件。收到HTTP请求后,先调用第一个中间件,在控制台输出一行信息,然后通过next方法,将执行权传给第二个中间件,输出HTTP回应。由于第二个中间件没有调用next方法,所以request对象就不再向后传递了。

  use方法内部可以对访问路径进行判断,据此实现简单的路由,根据不同的请求网址,返回不同的网页内容

var express = require("express");var http = require("http");var app = express();

app.use(function(request, response, next) {  if (request.url == "/") {
    response.writeHead(200, { "Content-Type": "text/plain" });
    response.end("Welcome to the homepage!\n");
  } else {
    next();
  }
});

app.use(function(request, response, next) {  if (request.url == "/about") {
    response.writeHead(200, { "Content-Type": "text/plain" });
  } else {
    next();
  }
});

app.use(function(request, response) {
  response.writeHead(404, { "Content-Type": "text/plain" });
  response.end("404 error!\n");
});

http.createServer(app).listen(1337);
登入後複製

  上面代码通过request.url属性,判断请求的网址,从而返回不同的内容。注意,app.use方法一共登记了三个中间件,只要请求路径匹配,就不会将执行权交给下一个中间件。因此,最后一个中间件会返回404错误,即前面的中间件都没匹配请求路径,找不到所要请求的资源。

  除了在回调函数内部判断请求的网址,use方法也允许将请求网址写在第一个参数。这代表,只有请求路径匹配这个参数,后面的中间件才会生效。无疑,这样写更加清晰和方便

app.use('/path', someMiddleware);
登入後複製

  上面代码表示,只对根目录的请求,调用某个中间件。

  因此,上面的代码可以写成下面的样子

var express = require("express");var http = require("http");var app = express();

app.use("/home", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the homepage!\n");
});

app.use("/about", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("Welcome to the about page!\n");
});

app.use(function(request, response) {
  response.writeHead(404, { "Content-Type": "text/plain" });
  response.end("404 error!\n");
});

http.createServer(app).listen(1337);
登入後複製

 

托管静态资源

  上面介绍了, express.static 是 Express 唯一内置的中间件,负责在 Express 应用中提托管静态资源,例如图片、CSS、JavaScript 文件等

express.static(root, [options])

  参数 root 指提供静态资源的根目录,可选的 options 参数拥有如下属性

属性          类型      缺省值     描述
dotfiles      String   “ignore”   是否对外输出文件名以点开头的文件。可选值为allow、deny和ignore
etag          Boolean   true     是否启用 etag 生成
extensions    Array    []       设置文件扩展名备份选项
index          Mixed    “index.html” 发送目录索引文件,设置为 false 禁用目录索引。
lastModified    Boolean  true  设置Last-Modified头为文件在操作系统上的最后修改日期。可选值为true或falsemaxAge          Number   0       以毫秒或者其字符串格式设置 Cache-Control 头的 max-age 属性。
redirect        Boolean  true     当路径为目录时,重定向至 “/”。
setHeaders      Function          设置 HTTP 头以提供文件的函数。
登入後複製
var options = {
  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));
登入後複製

  一般地,如果不需要特殊的设置,将静态资源文件所在的目录作为参数传递给 express.static 中间件就可以提供静态资源文件的访问了。例如,假设在 public 目录放置了图片、CSS 和 JavaScript 文件

app.use(express.static('public'));
登入後複製

  现在,public 目录下面的文件就可以访问了

http://localhost:3000/images/kitten.jpghttp://localhost:3000/css/style.csshttp://localhost:3000/js/app.jshttp://localhost:3000/images/bg.pnghttp://localhost:3000/hello.html
登入後複製

  如果静态资源存放在多个目录下面,可以多次调用 express.static 中间件:

app.use(express.static('public'));
app.use(express.static('files'));
登入後複製

  访问静态资源文件时,express.static 中间件会根据目录添加的顺序查找所需的文件。

  如果希望所有通过 express.static 访问的文件都存放在一个“虚拟(virtual)”目录(即目录根本不存在)下面,可以通过为静态资源目录指定一个挂载路径的方式来实现,如下所示:

app.use('/static', express.static('public'));
登入後複製

  现在,可以通过带有 “/static” 前缀的地址来访问 public 目录下面的文件了

http://localhost:3000/static/images/kitten.jpghttp://localhost:3000/static/css/style.csshttp://localhost:3000/static/js/app.jshttp://localhost:3000/static/images/bg.pnghttp://localhost:3000/static/hello.html
登入後複製

 

常用中间件

【cookie-parser()】

  用于解析cookie的中间件,添加中间后,req具备cookies属性。通过req.cookies.xxx可以访问cookie的值

$ npm install cookie-parser
登入後複製
登入後複製
var cookieParser = require('cookie-parser')
app.use(cookieParser(secret, options))
登入後複製

  secret 是可选参数,用于对cookie进行签名 ,通过它可以判断出客户是否修改了cookie,这是处于安全考虑,这个参数是任意字符串

  options 可选参数,是一个json对象,可选项包括path、expires、maxAge、domain、secure、httpOnly

var express      = require('express')var cookieParser = require('cookie-parser') 
var app = express()
app.use(cookieParser())
 
app.get('/', function(req, res) {
  console.log('Cookies: ', req.cookies)
})
 
app.listen(8080)
登入後複製

【express-session】

  session运行在服务器端,当客户端第一次访问服务器时,可以将客户的登录信息保存。 当客户访问其他页面时,可以判断客户的登录状态,做出提示,相当于登录拦截。session可以和Redis或者数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)丢失。

  当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session对象,生成一个类似于key,value的键值对, 然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带key(cookie),找到对应的session(value)。客户的信息都保存在session中

$ npm install express-session
登入後複製
var express = require('express')var session = require('express-session')var app = express()
app.use(session(options))
登入後複製

  options 常用选项如下:

  name - 默认'connect.sid',可自定义

  store - session 储存器实例

  secret - 用于对cookie进行签名 ,通过它可以判断出客户是否修改了cookie,这是处于安全考虑,这个参数是任意字符串

  cookie - 对session cookie的设置 。默认值 { path: '/', httpOnly: true, secure: false, maxAge: null }

  genid -  是个函数,调用它来生成一个新的会话ID。 (默认:使用UID2库)

  rolling -  强制对每个响应的Cookie,重置到期日期。 (默认:false)

  resave - 每一次都重新保存,即使没修改过(默认:true)

  proxy - ture/false,是否支持trust proxy,,需要设置 app.enable('trust proxy');一般来说,无需设置

  常用方法如下:

  Session.destroy() :删除session,当检测到客户端关闭时调用

  Session.reload() :当session有修改时,刷新session

  Session.regenerate() :将已有session初始化

  Session.save() :保存session

var express = require('express');var cookieParser = require('cookie-parser');var session = require('express-session');
 
app.use(cookieParser('sessiontest'));
app.use(session({
 secret: 'sessiontest',//与cookieParser中的一致
 resave: true,
 saveUninitialized:true}));
登入後複製
//修改router/index.js,第一次请求时保存一条用户信息。router.get('/', function(req, res, next) { var user={
  name:"Chen-xy",
  age:"22",
  address:"bj"
 }
 req.session.user=user;
 res.render('index', {
  title: 'the test for nodejs session' ,
  name:'sessiontest'
 });
});
登入後複製
//修改router/users.js,判断用户是否登陆。router.get('/', function(req, res, next) { if(req.session.user){  var user=req.session.user;  var name=user.name;
  res.send('你好'+name+',欢迎来到我的家园。');
 }else{
  res.send('你还没有登录,先登录下再试试!');
 }
});
登入後複製

【serve-favicon】

  设置网站的 favicon图标

$ npm install serve-favicon
登入後複製
var express = require('express')var favicon = require('serve-favicon')var path = require('path') 
var app = express()
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) 
// Add your routes here, etc.  app.listen(3000)
登入後複製

【body-parser】

  bodyParser用于解析客户端请求的body中的内容,内部使用JSON编码处理,url编码处理以及对于文件的上传处理

$ npm install body-parser
登入後複製
var bodyParser = require('body-parser')
登入後複製

  1、底层中间件用法:这将拦截和解析所有的请求;也即这种用法是全局的。

var express = require('express')var bodyParser = require('body-parser')  
var app = express()  
// parse application/x-www-form-urlencodedapp.use(bodyParser.urlencoded({ extended: false }))  
// parse application/jsonapp.use(bodyParser.json())
  
app.use(function (req, res) {
 res.setHeader('Content-Type', 'text/plain')
 res.write('you posted:\n')
 res.end(JSON.stringify(req.body, null, 2))
})
登入後複製

  use方法调用body-parser实例;且use方法没有设置路由路径;这样的body-parser实例就会对该app所有的请求进行拦截和解析

  2、特定路由下的中间件用法:这种用法是针对特定路由下的特定请求的,只有请求该路由时,中间件才会拦截和解析该请求;也即这种用法是局部的;也是最常用的一个方式

var express = require('express')var bodyParser = require('body-parser')  
var app = express()  
// create application/json parservar jsonParser = bodyParser.json()  
// create application/x-www-form-urlencoded parservar urlencodedParser = bodyParser.urlencoded({ extended: false })  
// POST /login gets urlencoded bodiesapp.post('/login', urlencodedParser, function (req, res) { if (!req.body) return res.sendStatus(400)
 res.send('welcome, ' + req.body.username)
})  
// POST /api/users gets JSON bodiesapp.post('/api/users', jsonParser, function (req, res) { if (!req.body) return res.sendStatus(400) // create user in req.body})
登入後複製

  express的post(或者get)方法调用body-parser实例;且该方法有设置路由路径;这样的body-parser实例就会对该post(或者get)的请求进行拦截和解析

  3、设置Content-Type 属性;用于修改和设定中间件解析的body内容类型

// parse various different custom JSON types as JSONapp.use(bodyParser.json({ type: 'application/*+json' }); 
// parse some custom thing into a Bufferapp.use(bodyParser.raw({ type: 'application/vnd.custom-type' })); 
// parse an HTML body into a stringapp.use(bodyParser.text({ type: 'text/html' }));
登入後複製

【morgan】

  Mogran是一个node.js关于http请求的express默认的日志中间件

npm install  morgan
登入後複製

  在basic.js中添加如下代码

var express = require('express');var app = express();var morgan = require('morgan');

app.use(morgan('short'));
app.use(function(req, res, next){
    res.send('ok');
});

app.listen(3000);
登入後複製

  node basic.js运行程序,并在浏览器里访问 http://127.0.0.1:3000 ,打印日志如下

::1 - GET / HTTP/1.1 200 2 - 3.157 ms
::1 - GET / HTTP/1.1 304 - - 0.784 ms
登入後複製

  morgan支持stream配置项,可以通过它来实现将日志落地的效果,代码如下:

var express = require('express');var app = express();var morgan = require('morgan');var fs = require('fs');var path = require('path');var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'});

app.use(morgan('short', {stream: accessLogStream}));
app.use(function(req, res, next){
    res.send('ok');
});

app.listen(3000);
登入後複製

  morgan的API非常少,使用频率最高的就是morgan(),作用是返回一个express日志中间件

morgan(format, options)
登入後複製

  参数说明如下:

  format:可选,morgan与定义了几种日志格式,每种格式都有对应的名称,比如combined、short等,默认是default

  options:可选,配置项,包含stream(常用)、skip、immediate

  stream:日志的输出流配置,默认是process.stdout

  skip:是否跳过日志记录

  immediate:布尔值,默认是false。当为true时,一收到请求,就记录日志;如果为false,则在请求返回后,再记录日志

 

路由

【路由方法】

  针对不同的请求,Express提供了use方法的一些别名,这些别名是和 HTTP 请求对应的路由方法: getpostputheaddeleteoptionstracecopylockmkcolmovepurgepropfindproppatchunlockreportmkactivitycheckoutmergem-searchnotifysubscribeunsubscribepatchsearch 和 connect

  app.all() 是一个特殊的路由方法,没有任何 HTTP 方法与其对应,它的作用是对于一个路径上的所有请求加载中间件

  有些路由方法名不是合规的 JavaScript 变量名,此时使用括号记法,比如 app['m-search']('/', function ...

var express = require("express");var http = require("http");var app = express();

app.all("*", function(request, response, next) {
  response.writeHead(200, { "Content-Type": "text/plain" });
  next();
});

app.get("/", function(request, response) {
  response.end("Welcome to the homepage!");
});

app.get("/about", function(request, response) {
  response.end("Welcome to the about page!");
});

app.get("*", function(request, response) {
  response.end("404!");
});

http.createServer(app).listen(1337);
登入後複製

  上面代码的all方法表示,所有请求都必须通过该中间件,参数中的“*”表示对所有路径有效。get方法则是只有GET动词的HTTP请求通过该中间件,它的第一个参数是请求的路径。由于get方法的回调函数没有调用next方法,所以只要有一个中间件被调用了,后面的中间件就不会再被调用了

【路由路径】

  路由方法的第一个参数,都是请求的路径,称为路由路径,它可以是字符串、字符串模式或者正则表达式

  1、字符串匹配

// 匹配 /about 路径的请求app.get('/about', function (req, res) {
  res.send('about');
});
登入後複製

  2、字符串模式匹配

// 匹配 acd 和 abcdapp.get('/ab?cd', function(req, res) {
  res.send('ab?cd');
});
登入後複製

  3、正则表达式匹配

// 匹配任何路径中含有 a 的路径:app.get(/a/, function(req, res) {
  res.send('/a/');
});
登入後複製

【路由句柄】

  可以为请求处理提供多个回调函数,其行为类似中间件。唯一的区别是这些回调函数可能调用 next('route') 方法而略过其他路由回调函数。可以利用该机制为路由定义前提条件,如果在现有路径上继续执行没有意义,则可将控制权交给剩下的路径

  路由句柄有多种形式,可以是一个函数、一个函数数组,或者是两者混合

  1、使用一个回调函数处理路由

app.get('/example/a', function (req, res) {
  res.send('Hello from A!');
});
登入後複製

  2、使用多个回调函数处理路由

app.get('/example/b', function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from B!');
});
登入後複製

  3、使用回调函数数组处理路由

var cb0 = function (req, res, next) {
  console.log('CB0');
  next();
}var cb1 = function (req, res, next) {
  console.log('CB1');
  next();
}var cb2 = function (req, res) {
  res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1, cb2]);
登入後複製

  4、混合使用函数和函数数组处理路由

var cb0 = function (req, res, next) {
  console.log('CB0');
  next();
}var cb1 = function (req, res, next) {
  console.log('CB1');
  next();
}
app.get('/example/d', [cb0, cb1], function (req, res, next) {
  console.log('response will be sent by the next function ...');
  next();
}, function (req, res) {
  res.send('Hello from D!');
});
登入後複製

【链式路由句柄】

  可使用 app.route() 创建路由路径的链式路由句柄。由于路径在一个地方指定,这样做有助于创建模块化的路由,而且减少了代码冗余和拼写错误

app.route('/book')
  .get(function(req, res) {
    res.send('Get a random book');
  })
  .post(function(req, res) {
    res.send('Add a book');
  })
  .put(function(req, res) {
    res.send('Update the book');
  });
登入後複製

 

路由器实例

  从Express 4.0开始,路由器功能成了一个单独的组件Express.Router。它好像小型的express应用程序一样,有自己的use、get、param和route方法

  可使用 express.Router 类创建模块化、可挂载的路由句柄。Router 实例是一个完整的中间件和路由系统,因此常称其为一个 “mini-app”

【基本用法】

  首先,Express.Router是一个构造函数,调用后返回一个路由器实例。然后,使用该实例的HTTP动词方法,为不同的访问路径,指定回调函数;最后,挂载到某个路径

var express = require('express');var router = express.Router();
router.get('/', function(req, res) {
  res.send('首页');
});
router.get('/about', function(req, res) {
  res.send('关于');
});
app.use('/', router);
登入後複製

  上面代码先定义了两个访问路径,然后将它们挂载到根目录。如果最后一行改为app.use(‘/app’, router),则相当于为/app/app/about这两个路径,指定了回调函数。

  这种路由器可以自由挂载的做法,为程序带来了更大的灵活性,既可以定义多个路由器实例,也可以为将同一个路由器实例挂载到多个路径

【router.route方法】

  router实例对象的route方法,可以接受访问路径作为参数

var express = require('express');var router = express.Router();
router.route('/api')
    .post(function(req, res) {// ...    })
    .get(function(req, res) {
        Bear.find(function(err, bears) {if (err) res.send(err);
            res.json(bears);
        });
    });
app.use('/', router);
登入後複製

【router中间件】

  use方法为router对象指定中间件,在数据正式发给用户之前,对数据进行处理。下面是一个中间件的例子

router.use(function(req, res, next) {
    console.log(req.method, req.url);
    next();    
});
登入後複製

  上面代码中,回调函数的next参数,表示接受其他中间件的调用。函数体中的next(),表示将数据传递给下一个中间件

  [注意]中间件放置顺序很重要,等同于执行顺序。而且,中间件必须放在HTTP动词方法之前,否则不会执行

【对路径参数的处理】

  router对象的param方法用于路径参数的处理

router.param('name', function(req, res, next, name) {// 对name进行验证或其他处理……    console.log(name);
    req.name = name;
    next();    
});
router.get('/hello/:name', function(req, res) {
    res.send('hello ' + req.name + '!');
});
登入後複製

  上面代码中,get方法为访问路径指定了name参数,param方法则是对name参数进行处理

  [注意]param方法必须放在HTTP动词方法之前

【实例】

  下面的实例程序创建了一个路由模块,并加载了一个中间件,定义了一些路由,并且将它们挂载至应用路径上

  在 app 目录下创建名为 birds.js 的文件,内容如下:

var express = require('express');var router = express.Router();// 该路由使用的中间件router.use(function timeLog(req, res, next) {
  console.log('Time: ', Date.now());
  next();
});// 定义网站主页的路由router.get('/', function(req, res) {
  res.send('Birds home page');
});// 定义 about 页面的路由router.get('/about', function(req, res) {
  res.send('About birds');
});

module.exports = router;
登入後複製

  然后在应用中加载路由模块:

var birds = require('./birds');
...
app.use('/birds', birds);
登入後複製

  应用即可处理发自 /birds 和 /birds/about 的请求,并且调用为该路由指定的 timeLog 中间件

 

响应方法

  response对象包含以下9个方法,response对象的方法向客户端返回响应,终结请求响应的循环。如果在路由句柄中一个方法也不调用,来自客户端的请求会一直挂起

方法           描述
res.download()    提示下载文件。
res.end()        终结响应处理流程。
res.json()       发送一个 JSON 格式的响应。
res.jsonp()      发送一个支持 JSONP 的 JSON 格式的响应。
res.redirect()    重定向请求。
res.render()     渲染视图模板。
res.send()       发送各种类型的响应。
res.sendFile()    以八位字节流的形式发送文件。
res.sendStatus()  设置响应状态代码,并将其以字符串形式作为响应体的一部分发送。
登入後複製

  1、response.download方法

//下载路径为'/report-12345.pdf'的文件res.download('/report-12345.pdf');//下载路径为'/report-12345.pdf'的文件,并将文件命名为 'report.pdf'res.download('/report-12345.pdf', 'report.pdf');//下载路径为'/report-12345.pdf'的文件,将文件命名为 'report.pdf',并且回调res.download('/report-12345.pdf', 'report.pdf', function(err){  if (err) {
  } else {
  }
});
登入後複製

  2、response.end方法

//终结响应处理流程res.end();//设置响应码为404,并终结响应处理流程res.status(404).end();
登入後複製

  3、response.json方法

res.json(null)
res.json({ user: 'tobi' })
res.status(500).json({ error: 'message' })
登入後複製

  4、response.jsonp方法

res.jsonp(null)
res.jsonp({ user: 'tobi' })
res.status(500).jsonp({ error: 'message' })
登入後複製

  5、response.redirect方法

res.redirect('/foo/bar');
res.redirect('http://example.com');
res.redirect(301, 'http://example.com');
res.redirect('../login');
登入後複製

  6、response.render方法

res.render('index');
res.render('index', function(err, html) {
  res.send(html);
});
res.render('user', { name: 'Tobi' }, function(err, html) {  // ...});
登入後複製

  7、response.send方法

res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
登入後複製

  8、response.sendFile方法

response.sendFile("/path/to/anime.mp4");
登入後複製

  9、response.sendStatus方法

res.sendStatus(200); // 'OK'res.sendStatus(403); // 'Forbidden'res.sendStatus(404); // 'Not Found'res.sendStatus(500); // 'Internal Server Error'
登入後複製

 

请求方法

【req.params】

// GET /user/tjreq.params.name// => "tj"// GET /file/javascripts/jquery.jsreq.params[0]// => "javascripts/jquery.js?1.1.11"
登入後複製

【req.query】

// GET /search?q=tobi+ferretreq.query.q// => "tobi ferret"// GET /shoes?order=desc&shoe[color]=blue&shoe[type]=conversereq.query.order// => "desc"req.query.shoe.color// => "blue"req.query.shoe.type// => "converse"
登入後複製

【req.body】

// POST user[name]=tobi&user[email]=tobi@learnboost.comreq.body.user.name// => "tobi"req.body.user.email// => "tobi@learnboost.com"// POST { "name": "tobi" }req.body.name// => "tobi"
登入後複製

【req.param(name)】

// ?name=tobireq.param('name')// => "tobi"// POST name=tobireq.param('name')// => "tobi"// /user/tobi for /user/:name req.param('name')// => "tobi"
登入後複製

【req.cookies】

// Cookie: name=tjreq.cookies.name// => "tj"
登入後複製

【req.ip】

req.ip// => "127.0.0.1"
登入後複製

req<span class="token punctuation">.path</span>

// example.com/users?sort=descreq.path// => "/users"
登入後複製

【req.host】

// Host: "example.com:3000"req.host// => "example.com"
登入後複製

 

app方法

【set方法】

  set方法用于指定变量的值

app.set("views", __dirname + "/views");
app.set("view engine", "jade");
登入後複製

  上面代码使用set方法,为系统变量“views”和“view engine”指定值

【get方法】

  除了作为use()方法的别名用法外,get方法还用于获取变量的值,与set方法相对应

app.get('title');// => undefinedapp.set('title', 'My Site');
app.get('title');// => "My Site"
登入後複製

【app.enable(name)】

  将设置项 name 的值设为 true 

app.enable('trust proxy');
app.get('trust proxy');// => true
登入後複製

【app.disable(name)】

  将设置项 name 的值设为 false 

app.disable('trust proxy');
app.get('trust proxy');// => false
登入後複製

【app.enabled(name)】

  检查设置项 name 是否已启用

app.enabled('trust proxy');// => falseapp.enable('trust proxy');
app.enabled('trust proxy');// => true
登入後複製

【app.disabled(name)】

  检查设置项 name 是否已禁用

app.disabled('trust proxy');// => trueapp.enable('trust proxy');
app.disabled('trust proxy');// => false
登入後複製

【app.engine(ext, callback)】

  注册模板引擎的 callback 用来处理 ext 扩展名的文件

  默认情况下, 根据文件扩展名 require() 加载相应的模板引擎。 比如想渲染一个 “foo.jade” 文件,Express 会在内部执行下面的代码,然后会缓存 require() ,这样就可以提高后面操作的性能

app.engine('jade', require('jade').__express);
登入後複製

  那些没有提供 .__express 的或者想渲染一个文件的扩展名与模板引擎默认的不一致的时候,也可以用这个方法。比如想用EJS模板引擎来处理 “.html” 后缀的文件:

app.engine('html', require('ejs').renderFile);
登入後複製

  这个例子中 EJS 提供了一个 .renderFile() 方法和 Express 预期的格式: (path, options, callback) 一致, 因此可以在内部给这个方法取一个别名 ejs.__express ,这样就可以使用 “.ejs” 扩展而不需要做任何改动

  有些模板引擎没有遵循这种转换, 这里有一个小项目 consolidate.js专门把所有的node流行的模板引擎进行了包装,这样它们在 Express 内部看起来就一样了。

var engines = require('consolidate');
app.engine('haml', engines.haml);
app.engine('html', engines.hogan);
登入後複製

【app.locals】

  应用程序本地变量会附加给所有的在这个应用程序内渲染的模板。这是一个非常有用的模板函数,就像应用程序级数据一样

app.locals.title = 'My App';
app.locals.strftime = require('strftime');
登入後複製

  app.locals 对象是一个 JavaScript Function,执行的时候它会把属性合并到它自身,提供了一种简单展示已有对象作为本地变量的方法。

app.locals({
  title: 'My App',
  phone: '1-250-858-9990',
  email: 'me@myapp.com'});

app.locals.title// => 'My App'app.locals.email// => 'me@myapp.com'
登入後複製

  app.locals 对象最终会是一个 Javascript 函数对象,不可以使用 Functions 和 Objects 内置的属性,比如 name、apply、bind、call、arguments、length、constructor。

app.locals({name: 'My App'});

app.locals.name// => 返回 'app.locals' 而不是 'My App' (app.locals 是一个函数 !)// => 如果 name 变量用在一个模板里,则返回一个 ReferenceError
登入後複製

  默认情况下Express只有一个应用程序级本地变量,它是 settings

app.set('title', 'My App');// 在 view 里使用 settings.title
登入後複製

【app.render(view, [options], callback)】

  渲染 view , 回调函数 callback 用来处理返回的渲染后的字符串。这个是 res.render() 的应用程序级版本,它们的行为是一样的。

app.render('email', function(err, html){// ...});

app.render('email', { name: 'Tobi' }, function(err, html){// ...});
登入後複製

【app.listen()】

  在给定的主机和端口上监听请求,这个和 node 文档中的 http.Server#listen() 是一致的。

var express = require('express');var app = express();
app.listen(3000);
登入後複製

  express() 返回的 app 实际上是一个 JavaScript Function,它被设计为传给 node 的 http servers 作为处理请求的回调函数。因为 app 不是从 HTTP 或者 HTTPS 继承来的,它只是一个简单的回调函数,可以以同一份代码同时处理 HTTP 和 HTTPS 版本的服务。

var express = require('express');var https = require('https');var http = require('http');var app = express();

http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
登入後複製

  app.listen() 方法只是一个快捷方法,如果想使用 HTTPS ,或者同时提供 HTTP 和 HTTPS ,可以使用上面的代码。

app.listen = function(){  var server = http.createServer(this);  return server.listen.apply(server, arguments);
};
登入後複製

 

HTTPS

  使用Express搭建HTTPS加密服务器很简单

var fs = require('fs');var options = {
  key: fs.readFileSync('E:/ssl/myserver.key'),
  cert: fs.readFileSync('E:/ssl/myserver.crt'),
  passphrase: '1234'};var https = require('https');var express = require('express');var app = express();

app.get('/', function(req, res){
  res.send('Hello World Expressjs');
});var server = https.createServer(options, app);
server.listen(8084);
console.log('Server is running on port 8084');
登入後複製

 

模板引擎

  需要在应用中进行如下设置才能让 Express 渲染模板文件:

  views, 放模板文件的目录,比如: app.set('views', './views')

  view engine, 模板引擎,比如: app.set('view engine', 'jade')

  然后安装相应的模板引擎 npm 软件包

$ npm install jade --save
登入後複製

  一旦 view engine 设置成功,就不需要显式指定引擎,或者在应用中加载模板引擎模块,Express 已经在内部加载,如下所示

app.set('view engine', 'jade');
登入後複製

  在 views 目录下生成名为 index.jade 的 Jade 模板文件,内容如下:

html
  head
    title!= title
  body
    h1!= message
登入後複製

  然后创建一个路由渲染 index.jade 文件。如果没有设置 view engine,需要指明视图文件的后缀,否则就会遗漏它

app.get('/', function (req, res) {
  res.render('index', { title: 'Hey', message: 'Hello there!'});
});
登入後複製

  此时向主页发送请求,“index.jade” 会被渲染为 HTML

 

数据库

  为 Express 应用添加连接数据库的能力,只需要加载相应数据库的 Node.js 驱动即可。这里简要介绍如何为 Express 应用添加和使用一些常用的数据库 Node 模块

【mysql】

$ npm install mysql
登入後複製
var mysql      = require('mysql');var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'dbuser',
  password : 's3kreee7'});

connection.connect();

connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {  if (err) throw err;
  console.log('The solution is: ', rows[0].solution);
});

connection.end();
登入後複製

【MongoDB】

$ npm install mongoskin
登入後複製
var db = require('mongoskin').db('localhost:27017/animals');

db.collection('mamals').find().toArray(function(err, result) {  if (err) throw err;
  console.log(result);
});
登入後複製

 

上传文件

  首先,在网页插入上传文件的表单

<form action="/pictures/upload" method="POST" enctype="multipart/form-data">
  Select an image to upload:  <input type="file" name="image">
  <input type="submit" value="Upload Image">
</form>
登入後複製

  然后,服务器脚本建立指向/upload目录的路由。这时可以安装multer模块,它提供了上传文件的许多功能

var express = require('express');var router = express.Router();var multer = require('multer');var uploading = multer({
  dest: __dirname + '../public/uploads/',  // 设定限制,每次最多上传1个文件,文件大小不超过1MB
  limits: {fileSize: 1000000, files:1},
})
router.post('/upload', uploading, function(req, res) {})
module.exports = router
登入後複製

  上面代码是上传文件到本地目录。下面是上传到Amazon S3的例子。

  首先,在S3上面新增CORS配置文件

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
  </CORSRule>
</CORSConfiguration>
登入後複製

  上面的配置允许任意电脑向你的bucket发送HTTP请求。

  然后,安装aws-sdk

$ npm install aws-sdk --save
登入後複製

  下面是服务器脚本

var express = require('express');var router = express.Router();var aws = require('aws-sdk');
router.get('/', function(req, res) {
  res.render('index')
})var AWS_ACCESS_KEY = 'your_AWS_access_key'var AWS_SECRET_KEY = 'your_AWS_secret_key'var S3_BUCKET = 'images_upload'router.get('/sign', function(req, res) {
  aws.config.update({accessKeyId: AWS_ACCESS_KEY, secretAccessKey: AWS_SECRET_KEY});  var s3 = new aws.S3()  var options = {
    Bucket: S3_BUCKET,
    Key: req.query.file_name,
    Expires: 60,
    ContentType: req.query.file_type,
    ACL: 'public-read'
  }
  s3.getSignedUrl('putObject', options, function(err, data){if(err) return res.send('Error with S3')
    res.json({
      signed_request: data,
      url: 'https://s3.amazonaws.com/' + S3_BUCKET + '/' + req.query.file_name
    })
  })
})
module.exports = router
登入後複製

  上面代码中,用户访问/sign路径,正确登录后,会收到一个JSON对象,里面是S3返回的数据和一个暂时用来接收上传文件的URL,有效期只有60秒。

  浏览器代码如下

// HTML代码为// <br>Please select an image// <input type="file" id="image">// <br>// <img id="preview">document.getElementById("image").onchange = function() {  var file = document.getElementById("image").files[0]  if (!file) return
  sign_request(file, function(response) {
    upload(file, response.signed_request, response.url, function() {
      document.getElementById("preview").src = response.url
    })
  })
}function sign_request(file, done) {  var xhr = new XMLHttpRequest()
  xhr.open("GET", "/sign?file_name=" + file.name + "&file_type=" + file.type)
  xhr.onreadystatechange = function() {if(xhr.readyState === 4 && xhr.status === 200) {      var response = JSON.parse(xhr.responseText)
      done(response)
    }
  }
  xhr.send()
}function upload(file, signed_request, url, done) {  var xhr = new XMLHttpRequest()
  xhr.open("PUT", signed_request)
  xhr.setRequestHeader('x-amz-acl', 'public-read')
  xhr.onload = function() {if (xhr.status === 200) {
      done()
    }
  }
  xhr.send(file)
}
登入後複製

  上面代码首先监听file控件的change事件,一旦有变化,就先向服务器要求一个临时的上传URL,然后向该URL上传文件

 

开发实例

【静态网页模板】

  在项目目录之中,建立一个子目录views,用于存放网页模板。

  假定这个项目有三个路径:根路径(/)、自我介绍(/about)和文章(/article)。那么,app.js可以这样写:

var express = require('express');var app = express();
 
app.get('/', function(req, res) {
   res.sendfile('./views/index.html');
});
 
app.get('/about', function(req, res) {
   res.sendfile('./views/about.html');
});
 
app.get('/article', function(req, res) {
   res.sendfile('./views/article.html');
});
 
app.listen(3000);
登入後複製

  上面代码表示,三个路径分别对应views目录中的三个模板:index.html、about.html和article.html。另外,向服务器发送信息的方法,从send变成了sendfile,后者专门用于发送文件。

  假定index.html的内容如下:

<html>
<head>
   <title>首页</title>
</head>
<body>
<h1>Express Demo</h1>
<header>
<p>
   <a href="/">首页</a> - <a href="/about">自我介绍</a> - <a href="/article">文章</a>
</p>
</header>
</body>
</html>
登入後複製

  about.html内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>about</body>
</html>
登入後複製

  article.html内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>article</body>
</html>
登入後複製

  运行app.js后,访问http://localhost:3000/结果如下

  

 【动态网页模板】

  下面来制作一个动态网页网站,以使用ejs引擎为例

  npm install ejs
登入後複製

  将view engine修改为ejs,并将模板的后缀修改为.html

var express = require('express');var app = express();var ejs = require('ejs');// 指定模板文件的后缀名为htmlapp.set('view engine', 'html');//运行ejs引擎读取html文件app.engine('.html', ejs.__express);

app.get('/', function (req, res){
    res.render('index');
});

app.get('/about', function(req, res) {
    res.render('about');
});

app.get('/article', function(req, res) {
    res.render('article');
});
登入後複製

  接下来,新建数据脚本。渲染是指将数据代入模板的过程。实际运用中,数据都是保存在数据库之中的,这里为了简化问题,假定数据保存在一个脚本文件中

  在项目目录中,新建一个文件blog.js,用于存放数据。blog.js的写法符合CommonJS规范,使得它可以被require语句加载

// blog.js文件var entries = [
    {"id":1, "title":"第一篇", "body":"正文", "published":"7/2/2017"},
    {"id":2, "title":"第二篇", "body":"正文", "published":"7/3/2017"},
    {"id":3, "title":"第三篇", "body":"正文", "published":"7/4/2017"},
    {"id":4, "title":"第四篇", "body":"正文", "published":"7/5/2017"},
    {"id":5, "title":"第五篇", "body":"正文", "published":"7/10/2017"},
    {"id":6, "title":"第六篇", "body":"正文", "published":"7/12/2017"}
];
exports.getBlogEntries = function (){   return entries;
}
exports.getBlogEntry = function (id){   for(var i=0; i < entries.length; i++){      if(entries[i].id == id) return entries[i];
   }
}
登入後複製

  新建header.html和footer.html

<!-- views/header.html文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%=title %></title>
</head>
<body>
    
<!-- views/footer.html文件 -->
   <footer>
      <p>
         <a href="/">首页</a>
         <a href="/about">自我介绍</a>
      </p>
   </footer>      
</body>
</html>
登入後複製

  接着,新建模板文件index.html

<!-- views/index.html文件 -->
<% include header.html %>
<h1>文章列表</h1>
<% for(var i=0; i < entries.length; i++){  %>
    <p>
        <a href="/article/<%=entries[i].id %>"><%=entries[i].title %></a>
        <br>
          <span>时间: <%=entries[i].published %></span>        
    </p>
<% } %>  
<% include footer.html %>
登入後複製

  新建模板文件about.html

<!-- views/about.html文件 -->
<% include header.html %>
<h1><%=title %> </h1>
<p>正文</p>
<% include footer.html %>
登入後複製

  新建模板文件article.html

<!-- views/article.html文件 -->
<% include header.html %>
<h1><%=blog.title %></h1>
<p>时间: <%=blog.published %></p>
<p><%=blog.body %></p>
<% include footer.html %>
登入後複製

  最后,改写app.js文件

var express = require('express');var app = express();var ejs = require('ejs');// 加载数据模块var blogEngine = require('./blog');
 
app.set('view engine', 'html');
app.engine('html', ejs.__express);

app.get('/', function(req, res) {
   res.render('index',{title:"最近文章", entries:blogEngine.getBlogEntries()});
});
 
app.get('/about', function(req, res) {
   res.render('about', {title:"自我介绍"});
});
 
app.get('/article/:id', function(req, res) {   var entry = blogEngine.getBlogEntry(req.params.id);
   res.render('article',{title:entry.title, blog:entry});
});
 
app.listen(3000);
登入後複製

  上面代码中的render方法,现在加入了第二个参数,表示模板变量绑定的数据。

  现在重启node服务器,然后访问http://127.0.0.1:3000来查看结果

 

 

以上是express框架入門學習知識點總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1325
25
PHP教程
1273
29
C# 教程
1252
24
如何評估Java框架商業支援的性價比 如何評估Java框架商業支援的性價比 Jun 05, 2024 pm 05:25 PM

評估Java框架商業支援的性價比涉及以下步驟:確定所需的保障等級和服務等級協定(SLA)保證。研究支持團隊的經驗和專業知識。考慮附加服務,如昇級、故障排除和效能最佳化。權衡商業支援成本與風險緩解和提高效率。

PHP 框架的學習曲線與其他語言框架相比如何? PHP 框架的學習曲線與其他語言框架相比如何? Jun 06, 2024 pm 12:41 PM

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

Java框架的效能比較 Java框架的效能比較 Jun 04, 2024 pm 03:56 PM

根據基準測試,對於小型、高效能應用程序,Quarkus(快速啟動、低記憶體)或Micronaut(TechEmpower優異)是理想選擇。 SpringBoot適用於大型、全端應用程序,但啟動時間和記憶體佔用稍慢。

PHP 框架的輕量級選項如何影響應用程式效能? PHP 框架的輕量級選項如何影響應用程式效能? Jun 06, 2024 am 10:53 AM

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

golang框架文件最佳實踐 golang框架文件最佳實踐 Jun 04, 2024 pm 05:00 PM

編寫清晰全面的文件對於Golang框架至關重要。最佳實踐包括:遵循既定文件風格,例如Google的Go程式設計風格指南。使用清晰的組織結構,包括標題、子標題和列表,並提供導覽。提供全面且準確的信息,包括入門指南、API參考和概念。使用程式碼範例說明概念和使用方法。保持文件更新,追蹤變更並記錄新功能。提供支援和社群資源,例如GitHub問題和論壇。建立實際案例,如API文件。

如何為不同的應用場景選擇最佳的golang框架 如何為不同的應用場景選擇最佳的golang框架 Jun 05, 2024 pm 04:05 PM

根據應用場景選擇最佳Go框架:考慮應用類型、語言特性、效能需求、生態系統。常見Go框架:Gin(Web應用)、Echo(Web服務)、Fiber(高吞吐量)、gorm(ORM)、fasthttp(速度)。實戰案例:建構RESTAPI(Fiber),與資料庫互動(gorm)。選擇框架:效能關鍵選fasthttp,靈活Web應用選Gin/Echo,資料庫互動選gorm。

Java框架學習路線圖:不同領域中的最佳實踐 Java框架學習路線圖:不同領域中的最佳實踐 Jun 05, 2024 pm 08:53 PM

針對不同領域的Java框架學習路線圖:Web開發:SpringBoot和PlayFramework。持久層:Hibernate和JPA。服務端響應式程式設計:ReactorCore和SpringWebFlux。即時計算:ApacheStorm和ApacheSpark。雲端運算:AWSSDKforJava和GoogleCloudJava。

Golang框架學習過程中常見的迷思有哪些? Golang框架學習過程中常見的迷思有哪些? Jun 05, 2024 pm 09:59 PM

Go框架學習的迷思有以下5種:過度依賴框架,限制彈性。不遵循框架約定,程式碼難以維護。使用過時庫,帶來安全和相容性問題。過度使用包,混淆程式碼結構。忽視錯誤處理,導致意外行為和崩潰。

See all articles