Express詳解

安裝 express

在目標文件夾下執行以下命令:javascript

cnpm i express

安裝完後,在目標文件夾下新建index.js文件:css

// 引入 express 模塊
var express = require('express');

// 建立 express 實例
var app = express();

// 響應HTTP的GET方法
app.get('/', function (req, res) {
 res.send('Hello World!');
});

// 監聽到8000端口
app.listen(8000, function () {
 console.log('Hello World is listening at port 8000');
});

而後在Node.js的命令行環境下執行「node index.js」命令,網站就運行起來了。瀏覽器訪問一下,能夠輸出相應的信息。html

使用

const express = require("express");
const app = express();

// 處理文件路徑的模塊
const path = require("path");

// view處理
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");

// 定義一個存放靜態資源的目錄
app.use(express.static("src"));

// 頁面路由的處理,此處表示首頁的時候處理index
const index = require("./routes/index");
app.use("/", index);

const server = app.listen(8080, function(){
	console.log("啓動成功!");
})

Express中的路由與路由器

Express中的路由器分爲兩種類型:java

app類型的路由器常使用以下代碼建立:node

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

router類型的路由器常使用以下代碼建立:jquery

var express = require('express');
var router = express.Router();

 app和router是形爲function(request, response, next)形式的函數對象,使用app.verb(),router.verb()形式函數實現路由註冊(路由註冊本質上是一個觀察者模式)。web

app.verb()和router.verb()中的verb常使用use、get、post、put、delete、route等動詞,不一樣動詞管轄的HTTP請求方法範圍不一樣,這些動詞函數的參數形式常爲(pathExp, handleCallback)形式:其中pathExp表示請求路徑,可爲正則表達式;handleCallback爲路徑映射處理函數。正則表達式

app是Express框架所構建程序的請求處理入口,app可做爲頂層路由器使用,在應用中也可掛載下級路由器(使用router對象)以實現分級路由。express

中間件

Express 是一個自身功能極簡,徹底是由路由和中間件構成一個的 web 開發框架:從本質上來講,一個 Express 應用就是在調用各類中間件。npm

中間件(Middleware) 就是處理HTTP請求的函數,它最大的特色就是,一箇中間件處理完,再傳遞給下一個中間件。App實例在運行過程當中,會調用一系列的中間件。

每一箇中間件能夠從App實例,接收三個參數,依次爲request對象(表明HTTP請求)、response對象(表明HTTP迴應),next回調函數(表明下一個中間件)。每一箇中間件均可以對HTTP請求(request對象)進行加工,而且決定是否調用next方法,將request對象再傳給下一個中間件。

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);

當你不寫路徑的時候,實際上就至關於"/",就是全部網址

路由get、post這些東西,也是中間件,中間件講究順序,匹配上第一個以後,就不會日後匹配了,next函數纔可以繼續日後匹配。以下實例:

app.get("/",function(req,res,next){
    console.log("1");
    next();
});

app.get("/",function(req,res){
    console.log("2");
});

all方法和HTTP動詞方法

針對不一樣的請求,Express提供了use方法的一些別名。好比,上面代碼也能夠用別名的形式來寫。

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方法,因此只要有一箇中間件被調用了,後面的中間件就不會再被調用了。

除了get方法之外,Express還提供post、put、delete方法,即HTTP動詞都是Express的方法。

這些方法的第一個參數,都是請求的路徑。除了絕對匹配之外,Express容許模式匹配。

app.get("/hello/:who", function(req, res) {
  res.end("Hello, " + req.params.who + ".");
});

上面代碼將匹配「/hello/alice」網址,網址中的alice將被捕獲,做爲req.params.who屬性的值。須要注意的是,捕獲後須要對網址進行檢查,過濾不安全字符,上面的寫法只是爲了演示,生產中不該這樣直接使用用戶提供的值。

若是在模式參數後面加上問號,表示該參數可選。

app.get('/hello/:who?',function(req,res) {
	if(req.params.id) {
    	res.end("Hello, " + req.params.who + ".");
	}
    else {
    	res.send("Hello, Guest.");
	}
});

set方法

set方法用於指定變量的值。

app.set("views", __dirname + "/views");

app.set("view engine", "jade");

 上面代碼使用set方法,爲系統變量「views」和「view engine」指定值。

response對象

API 含義
res.app 同req.app
res.append() 追加指定HTTP頭
res.set() 在res.append()後將重置以前設置的頭
res.cookie() 設置Cookie
res.clearCookie() 清除Cookie
res.download() 傳送指定路徑的文件
res.get() 返回指定的HTTP頭
res.json() 傳送JSON響應
res.jsonp() 傳送JSONP響應
res.location() 只設置響應的Location HTTP頭,不設置狀態碼或者close response
res.redirect() 設置響應的Location HTTP頭,而且設置狀態碼302
res.send() 傳送HTTP響應
res.sendFile() 傳送指定路徑的文件 -會自動根據文件extension設定Content-Type
res.set() 設置HTTP頭,傳入object能夠一次設置多個頭
res.status() 設置HTTP狀態碼
res.type() 設置Content-Type的MIME類型

(1)response.redirect方法

response.redirect方法容許網址的重定向。

response.redirect("/hello/anime");
response.redirect("http://www.example.com");
response.redirect(301, "http://www.example.com"); 

res.redirect()默認響應狀態碼是302 

能夠更改這個狀態碼做爲res.redirect()的第一個參數

//app.js
var express = require('express');
var app = express();

app.get('/', function(req, res){
  res.redirect(302, 'demo');
});
app.get('/demo', function(req, res){
  res.end();
});

app.listen(3000);

當在url地址欄中輸入http://localhost:3000

頁面就會重定向到http://localhost:3000/demo

(2)response.sendFile方法

response.sendFile方法用於發送文件。

response.sendFile("/path/to/anime.mp4");

(3)response.render方法

response.render方法用於渲染網頁模板。

app.get("/", function(request, response) {
  response.render("index", { message: "Hello World" });
});

上面代碼使用render方法,將message變量傳入index模板,渲染成HTML網頁。

(4)res.send()

res.send用於向客戶端響應信息 

而且它的強大之處在於能夠智能的處理咱們傳遞的不一樣類型參數

app.get('/', function(req, res, next){
  res.send('express');
});

當參數爲字符串,會將響應頭Content-Type默認設置爲text/html

也就是解析爲html呈如今咱們的頁面上

app.get('/', function(req, res){
  res.send(200);
});

當參數爲數字,會自動幫咱們設置響應體(狀態碼…)

app.get('/', function(req, res){
  res.send([1, 2, 3]);
});

 當參數爲數組或對象,它會響應一個JSON

requst對象

API 含義
req.app 當callback爲外部文件時,用於訪問express的實例
req.baseUrl 獲取路由當前安裝的URL路徑
req.body/cookies 得到「請求主體」/ Cookies
req.fresh/stale 判斷請求是否還「新鮮」
req.hostname/ip 獲取主機名和IP地址
req.originalUrl 獲取原始請求URL
req.params 獲取路由的parameters
req.path 獲取請求路徑
req.protocol 獲取協議類型
req.query 獲取URL的查詢參數串
req.route 獲取當前匹配的路由
req.subdomains 獲取子域名
req.acceptsCharsets 返回指定字符集的第一個可接受字符編碼
req.acceptsEncodings 返回指定字符集的第一個可接受字符編碼
req.acceptsLanguages 返回指定字符集的第一個可接受字符編碼
req.accepts() 檢查可接受的請求的文檔類型
req.get() 獲取指定的HTTP請求頭
req.is() 判斷請求頭Content-Type的MIME類型

(1)request.ip

request.ip屬性用於得到HTTP請求的IP地址。

(2)request.files

request.files用於獲取上傳的文件。

(3)req.query

req.query能夠獲取請求路徑參數的對象

向服務器發送請求 http://localhost:3000/?user=tester&pass[a]=123&pass[b]=456

//app.js
var express = require('express');
var app = express();

app.get('/', function(req, res, next){
  console.log(req.query);
  console.log(req.query.user); //tester
  console.log(req.query.pass.a); //123
  console.log(req.query.pass.b); //456
  res.end();
});

app.listen(3000);

(4)req.params

req.params能夠解析複雜路由規則上的屬性 
(req.param綜合了req.query和req.param的功能,可是被移除了不要使用)

向服務器發送請求 http://localhost:3000/123456

//app.js
var express = require('express');
var app = express();

app.get('/:id', function(req, res, next){
  console.log(req.params.id); //123456
  res.end();
});

app.listen(3000);

這樣不論我在根路徑後輸入的是什麼都會被解析爲req.params.id 

靜態資源

靜態資源就是指咱們在開發中用到的css、js、img等等 

它們須要存放到一個靜態資源目錄 

當瀏覽器發出了一個非HTML文件請求 

服務器就會從這個靜態資源目錄下去查找文件 

咱們通常在根目錄下建立一個public文件來存儲 

並在public中建立stylesheets、javascripts、images等文件夾 

用來存儲特定類型的資源

指定靜態資源目錄的方法上面已經提到了

var path = require('path');
app.use(express.static(path.join(__dirname, 'public')));

好比說咱們的html中有這樣的代碼

<link href="/javascripts/jquery.js" rel="stylesheet" media="screen">

 那麼客戶端運行發出請求

服務器就會在public的javascripts文件夾下找到jquery.js靜態資源

模板引擎

express框架默認是ejs和jade渲染模板 

路由

路由的意思就是根據不一樣的路徑,來指定不一樣的處理方法 

咱們通常把不一樣的路由封裝進不一樣的模塊

首先在根目錄下建立一個文件夾routes存儲路由

如今我在routes文件夾下建立倆個路由文件index.js和users.js

修改app.js

//app.js
var express = require('express');
var path = require('path');
var app = express();

var index = require('./routes/index');
var users = require('./routes/users');

app.use('/', index);
app.use('/users', users);

app.listen(3000);

這樣表示http://localhost:3000/的路由交給index處理 
http://localhost:3000/users的路由交給users處理

下面簡單的實現一下路由

//routes/index.js
var express = require('express');
var router = express.Router();

router.get('/', function(req, res){
  res.end('index');
});

router.get('/123', function(){
  res.end(123);
});

module.exports = router;

 

//routes/users.js
var express = require('express');
var router = express.Router();

router.get('/', function(req, res) {
  res.end('users');
});

module.exports = router;

經過express.Router()建立的router就像一個mini版的app同樣

app能作的,router都能作 

只是咱們把邏輯都封裝到了各個路由模塊中

上面代碼的結果:

 

body-parser中間件

其實express在3.x版本中內置了不少中間件

可是4.x版本就將出static之外的全部中間件所有抽離出來了

因此就須要咱們單獨安裝

對照表以下:

Express 3.0 Express 4.0
bodyParser body-parser
compress compression
cookieSession cookie-session
logger morgan
cookieParser cookie-parser
session express-session
favicon static-favicon
response-time response-time
error-handler errorhandler
method-override method-override
timeout connect-timeout
vhost vhost
csrf csurf

剛纔就提到了POST請求有所不一樣

不一樣的地方就在於咱們須要body-parser這個中間件來處理數據

經過req.body來得到數據

首先使用前不要忘記下載

npm install body-parser --save
//app.js
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.get('/', function(req, res){
  res.send('<form method="POST" action="./form">\
              <input type="text" name="user">\
              <input type="submit">\
            </form>');
});
app.post('/form', function(req, res){
  console.log(req.body);
  var user = req.body.user;
  res.send('帳號: ' + user);
});

app.listen(3000);

 下面這四個方法分別用於對body內容採起不一樣的處理方法

bodyParser.json(options) 處理JSON數據

bodyParser.raw(options) 處理buffer數據

bodyParser.text(options) 處理文本數據

bodyParser.urlencoded(options) 處理UTF-8編碼數據

這樣我首先經過get請求獲取主頁面

提交表單向服務器發送post請求

服務器響應結果

express-generator:使用express搭建應用結構

express模塊有一個命令行工具express,能夠用來生成基於express模塊的應用結構(網站結構)。

express 4.x以後,express命令被獨立出來放在了express-generator模塊中。咱們用下面的命令全局安裝express這個命令行工具:

cnpm install -g express-generator

安裝完成後,在命令行環境下執行「express --version」,能夠看到express的版本是4.16.1。

好了,如今咱們使用express命令來建立一個默認的網站。

在命令行環境下導航到node.js這個目錄下,執行下面的命令:

express FirstExpress

而後能夠看到:

仔細看上面的圖哦,它告訴了咱們三類很是重要的信息:

express命令建立的網站的目錄結構以及建立的文件

安裝依賴(進入到HelloExpress下,執行npm install)

使用npm start啓動網站(express 4.x後)

按照響應的提示依次執行:

cd FirstExpress

cnpm install

npm start

很快就能夠看到下面的圖:

看到上圖,說明網站已正常運行。你能夠在瀏覽器裏訪問http://localhost:3000,而後就能夠看到這個頁面:

到這裏,express框架就搭建成功!

最後附上API中文地址:https://cloud.tencent.com/developer/section/1489347

相關文章
相關標籤/搜索