express4.x API中文文檔

原文在這里http://www.expressjs.com.cn/4x/api.html發現這不支持表格,表格內容沒有翻譯,因為水平有限,部分語句可能存在錯誤,之后我會陸續更正,同時使語句更加通順。

一、express()

創建一個Express應用,express()是一個由express模塊導出的入口(top-level)函數.

var express=require("express");
var app=express();
內置方法

express.static(root,[options])
express.static是一個Express內置的一個唯一的一個中間件,是基于server-static開發的,負責托管Express應用內的靜態資源。
root參數指的是靜態資源文件所在的根目錄。
options對象是可選的,支持以下屬性:

1、dotfiles:對點文件(以點開頭的文件)提供服務,可能的值"allow"、"deny"、"ignore",默認值是ignore

2、etag

3、extensions:設置文件的拓展回退,默認值為false

4、index:設置目錄的首頁文件,設置為false時禁止使用目錄首頁默認值為"index.html"

5、lastModefied:設置Last-Modified頭到操作系統上的文件的最后修改日期,默認為true

6、maxAge:設置Cache-Control頭文件的max-age屬性,單位是毫秒,也可以是ms format格式的字符串,默認值為0

7、redirect:當請求路徑是一個目錄時,重定向到尾部添加"/",默認值是true

8、setHeader:設置響應文件的http頭文件

關于此中間件的細節,請參考通過Express托管靜態資源文件

二、Application

app對象一般是Express應用程序,通過使用入口函數express()導出

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

app.get("/",function(req,res){
    res.send("hello world");
});
app.listen(3000);

app對象有處理以下事務的一些方法:

  • 處理http請求的路由:請看app.METHOD和app.param

  • 配置中間件:請看app.route

  • 渲染HTML視圖:請看app.render

  • 設置模板引擎:請看app.engine

app同樣可以設置一些影響app工作的屬性,獲取更多信息,請看Application settings

屬性

app.locals

app.locals對象是一個JavaScript對象,并且它的屬性是應用程序的本地變量

app.locals.title
// =>"My App"

app.locals.email
// =>"me@myapp.com"

一旦設置了app.locals的屬性,這個屬性就會存在于應用程序的整個生命周期,二而不同于res.locals設置的屬性只存在請求的生命周期中

你可以在應用程序的模板中使用本地變量,這對于模板和應用級數據來說提供了很有用的輔助功能,但是你在中間件中并不能訪問本地變量

app.locals.title="My App";
app.locals.strftime=require("strftime");
app.locals.email="me@myapp.com";

app.mountpath

app.mountpath屬性是子app加載的路徑

一個子app是express的實例,它可以作為路由句柄處理請求
var express=require("express");

var app=express();//the main app
var admin=express();//the sub app

admin.get("/",function(req,res){
    console.log(admin.moutpath);// /admin
    res.send("Admin Homepage");
})

app.use("/admin",admin);//mout the sub app

它有點像req對象的baseUrl屬性,除了req.baseUrl返回匹配的url路徑,而不是模式。

如果一個子應用加載了多種路徑模式,app.moutpath返回一個它加載的模式的列表,如下所示:

var admin=express();

admin.get("/",function(req,res){
    console.log(admin.mountpath);//["/adm*n","/manager"]
    res.send("Admin Homepage");
})

var secret=express();
secret.get("/",function(req,res){
    console.log(secret.mountpath);// /secr*t
    res.send("Admin Secret");
})

admin.use("/secr*t",secret);// load the "secret" router on "/secr*t",on the "admin" sub app
admin.use(["/adm*n","/manager"],admin);//load the "amdin" router on "/adm*n" and "/manager",on the parent app
事件

app.on("mount",claaback(parent))

這個事件當一個sub-app被掛載到一個父級應用程序時被觸發,父級應用程序會被當做是一個參數傳遞給回調函數

var admin=express();

admin.on("mount",function(parent){
    console.log("Admin Mounted");
    console.log(parent);  //refers to the parent app
})

admin.get("/",function(req,res){
    res.send("Admin Homepage");
});

app.use("/admin",admin);
方法

app.all(path,callback[,callback...])

這個方法就像標準的app.METHOD()方法,除了它還可以匹配所有http方法。

對于特定的路徑前綴或者是任意匹配映射全局邏輯。例如,你把下面的內容放在所有路由定義的前面,它要求所有從這個點開始的路由都需要加載認證和自動加載一個用戶,請記住這些回調函數并不一點是終點,loadUser可以像一個任務一樣,然后使用next()方法繼續匹配接下來的路由

app.all("*",requireAuthentication,loadUser);

相等于:

app.all("*",requireAuthentication);
app.all("*",loadUser);

另一個例子就是使用全局函數,這個例子很像前面的,但是這個把路徑限制了以"/api"開頭的路徑

app.all("/api/*",requireAuthentication);

app.delete(path,callback[,callback...])

HTTP DELETE路由請求到特定的路徑和特定的回調函數,獲取更多信息,參看routing guide

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。

app.delete("/",function(req,res){
    res.send("DELETE request to homepage")
})

app.disable(name)

name是一個app settings table的一個屬性,給name設置布爾值false,使用app.set("foo",false)相當于使用app.disable("foo");

例如:

app.disable("trust proxy);
app.get("trust proxy");
// =>false

app.disabled(name)

name是一個app settings table的一個屬性,如果給name設置disable(false),則返回true

app.disabled("trust proxy");
// =>true

app.enable("trust proxy");
app.disabled("trust proxy");
// =>false

app.enable(name)

name是一個app settings table的一個屬性,給name設置布爾值true,使用app.set("foo",true)相當于使用app.enable("foo");

app.enable("trust proxy");
app.get("trust proxy");
// =>true

app.enabled(name)

name是一個app settings table的一個屬性,如果給name設置enable(true),則返回true

app.enabled("trust proxy");
// =>false

app.enable("trust proxy");
app.enabled("trust proxy");
// =>true

app.engine(ext,callback)

設置模板引擎來渲染

默認情況下,Express需要使用require()來加載基于文件后綴名的引擎,例如,如果你想要渲染一個名為"foo.jade"的文件,Express在內部調用下面的內容,并且緩存require()的結果以供后續調用,以此來提高性能

app.enging("jade",require("jade").__express);

為那些沒有使用.__express的引擎使用這個方法,或者你想對模板引擎做一個不一樣的拓展。

例如,使EJS模板引擎匹配".html"文件

app.engine("html",require("ejs).renderFile);

在這個情況下,EJS提供了一個和Express希望的擁有(path,options,callback)的.renderFile()方法,盡管說明了這個方法在ejs._express的內部,所以你使用".ejs"為后綴名時,你不需要做什么。

一些模板引擎并不遵循這個慣例,consolidata.js這個庫可以使得這寫模板引擎遵循這個慣例,所以他們也可以和Express無縫緊密地工作

var engines=require("consolidate");
app.engine("haml",engines.haml);
app.engine("html",engines.hogan);

app.get(name)

返回應用程序設置的name的值,這個name是一個app setting table的一個字符串之一,例如:

app.get("title");
// =>undefined

app.set("title","My Site");
app.get("title");
// =>" My Site"

app.get(path,callback[,callback...])

特定路徑和回調函數的HTTP GET請求的路由,獲取更多信息,請看routing guide

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。

app.get("/",function(req,res){
    res.send("GET request to homepage");
})

app.listent(port,[hostname],[backlog],[callback])

綁定和監聽主機和端口,這個方法和node原生的http.Server.listen()相同

var express=require("express");
var app=express();
app.listen(3000);

由express()創建的app實例其實是一個JavaScript方法,app是作為node的http服務器的一個回調函數去處理請求。這使得很容易使用相同的代碼庫為你的應用程序同時提供http和https版本,以為app并不從這里繼承(它僅僅是一個方法)

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()方法是下面所示的一個簡便方法(僅僅對于HTTP而言):

app.listen=function(){
    var server=http.createServer(this);
    return server.listen.apply(server,arguments);

app.METHOD(path,callback[,callback])

當METHOD 是一個HTTP請求方法,比如小寫的GET、PUT、POST等,返回一個HTTP請求。因此,實際的方法是appp.get()、app.post()、app.put()等,請看以下完整列表。

獲取更多信息,請看routing guide

Expres支持以下路由方法,相等于響應的HTTP方法

checkout、connect、copy、delete、get、head、lock、merge、mkactivity、mkcol、move、m-search、notify、options、path、post、propfind、proppatch、purge、put、report、search、subscribe、trace、unlock、unsubscribe

通過以下方法將已有的JavaScript變量的名字轉化為路由方法,例如:app"m-search"...

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。

API文檔對最常用的HTTP方法app.get()、app.post()、app.put()和app.delete()有明確的條目列出,但是,在上面列出的其他方法其實也有相同的方式。

這里有個特別的路由方法app.all(),它不是像其他HTTP方法一樣工作,它在一個路徑上對所有HTTP請求方法加載同一個中間件

在下面的例子中,無論是使用GET,POST,PUT,DELETE或是其他任何HTTP請求方法請求"/secret",處理方法都會執行。

app.all("/secret",function(req,res,next){
    console.log("Accessing the secret section..."));
    next();//pass control to the next handle

app.param([name],callback)

為路由參數添加一個觸發回調函數,name是一個參數或者是一個name組成的數組,回調函數是一個方法。回調函數的參數是requset對象,response對象,next中間件和按照順序的name的值。

如果name是一個數組,回調函數觸發器按照這個數組中每個參數的聲明順序進行掛載。此外,除數組中最后一個參數外,在回調函數中調用next會調用數組中下一個參數的回調函數,對于數組中的最后一個參數, 調用next會調用這個路由正在處理的下一個中間件,就像它是一個string一樣

例如,當:user在一個路由路徑中,你可能需要匹配用戶加載邏輯去自動提供req.user的路徑或者展示參數輸入驗證

app.param("user",function(req,res,next,id){
    //try to get the user details from the User model and attach it to the request object
    User.find(id,function(err,user){
        if(err){
            next(err);
        }else if(user){
            req.user=user;
            next();
         }else{
            next(new Error("failed to load user"));
         }
      });
});

回調函數是他們本地定義的路由器,他們不是繼承自掛接的app或者是路由器,因此,定義在app中的param回調函數只會被定義在app路由器中定義的參數觸發

所有的param回調函數都會在其他出現param的路由處理之前調用,并且再一次請求和響應循環中,他們只會被調用一次,即使這個參數匹配在很多路由中,就像下面的例子一樣:

app.param("id",function(req,res,next,id){
    console.log("CALLED ONLY ONCE");
    next();
});

app.get("/user/:id",function(req,res,next){
    console.log("although this matches");
    next();
});

app.get("/user/:id",function(req,res){
    console.log("and this matches to");
    res.end();
})

On GET /user/42,打印出以下內容:

CALLED ONLY ONCE
although this matches
and this matched too
app.param(["id","page"],function(req,res,next,value){
    console.log("CALL ONLY ONCE with",value);
    next();
})

app.get("/user/:id/:page",function(req,res,next){
    console.log("although this matches");
    next();
});

app.get("/user/:id/:page",function(req,res){
    console.log("and this matches too");
    res.end();
});

On GET /user/42/3,打印出以下內容:

CALLED ONLY ONCE with 42
CALLED ONLY ONCE with 3
although this matched
and this matches too

app.path[name],callback)

返回應用程序的路徑字符串。

var app=express(),
      blog=express(),
      blogAdmin=express();

app.use("/blog",blog);
blog.use("/admin",blogAdmin);

console.log(app.path());//""
console.log(blog.path());//"/blog"
console.log(blogAdmin.path());//"/blog/admin"

這個方法在復雜掛載的app中會變得非常復雜,它總是比用req.baseUrl去獲取app的路徑更好

app.post(path,callback[,callback...])

特定路徑和回調函數的HTTP POST請求的路由,獲取更多信息,請看routing guide

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。

app.post("/",function(req,res){
    res.send("POST request to homepage");
});

app.put(path,callback[,callback...])

特定路徑和回調函數的HTTP PUT請求的路由,獲取更多信息,請看routing guide

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。

app.put("/",function(req,res){
    res.send("PUT request to homepage")
})

app.render(view,[locals],callback)

通過回調函數返回一個HTML視圖,它接受一個可選參數,這個變量是一個用于視圖的包含本地變量的對象,它很像res.render(),除了它不能發送給渲染的視圖給客戶端。

app.render()是非常有用的生成渲染視圖的函數,在res.render()內部是用app.render()來渲染視圖。

本地變量cache是為視圖緩存保留的,如果你想在開發中使用視圖緩存,可以將它設置為true,視圖緩存在生產環境中默認使用。

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

app.render("email",{name:"Tobi"},function(err,html){
//...
})

app.route(path)

返回一個單獨路由器的實例,然后你可以用它和可選的中間件來處理HTTP操作。用app.route()避免重復的路由名字(和錯字錯誤)

var app=express();

app.route("/event").all(function(req,res,next){
    //runs for all HTTP verb first
    //think of it as route specific middleware
})
.get(function(req,res,next){
    res.json(...);
})
.post(function(req,res,next){
    //maybe add a new event...
})

app.set(name,value)

給name分配一個值,name是app setting table中的一個屬性。

給一個布爾屬性調用app.set("foo",true)效果和調用app.enable("foo")是一樣的,同樣,給一個布爾屬性調用app.set("foo",false)效果和調用app.disable("foo")是一樣的。

通過app.get()方法取出設置的值

app.set("title","My title");
app.get("title");//" My title"

Application Setting

如果name是application settings中的一個,它會影響應用程序,完整的application settings列表如下:

app.use([path,]function[,function...])

在路徑中掛載中間件,如果沒有指定路徑,默認為"/"。

路由會匹配任何緊跟在"/"后面的路徑,例如,app.use("/apple",...)會匹配"/apple"、"/apple/images","/apple/images/news"等。

在一個中間件中,req.originalUrl是req.baseUrl和req.path的組合,就像下面的例子一樣

app.use("/admin",function(req,res,next){
    //GET "http://www.example.com/admin/new"
    console.log(req.originalUrl);//"/admin/new"
    console.log(req.baseUrl);//"/admin"
    console.log(req.path);//"/new"

在一個路徑中掛載一個中間件會使只要請求路徑的基礎地址匹配路徑就會觸發中間件的函數執行。因為路徑默認為“/”,中間件掛載沒有路徑會在app每一個請求時執行。

//this middleware will be executed for every request to the app
app.use(function(req,res,next){
    console.log("Time :%d",Date.now());
    next();
})

中間件函數是按順序執行的,因此中間件的順序是很重要的

//this middleware will not allow the request to go beyond it
ap.use(function(req,res,next)){
    res.send("Hello World");
})

//request will never reach this route
app.get("/",function(req,res){
    res.send("Welcome");
})

path可以是一個字符串,一個路徑模式,一個正則表達式去匹配路徑,或者是他們的組成的數組

function可以是一個中間件函數、一系列中間件函數、中間件函數組成的數組或者是他們的組合。因為router和app是中間件的接口,當你想要任何其他中間件函數的時候你可以使用他們。

下面是在一個Express app中使用express static中間件的一些例子。

服務應用程序文件夾中的“public”目錄中的靜態資源

//GET /style.css etc
app.use(express.static(__dirname+"/public"));

在路徑"/static"中掛載中間件僅僅當請求的路徑以"/static"開頭提供其中的靜態資源

//GET /static/style.css etc
app.use("/static",express.static(__dirname+"/public"));

通過在static中間件之后加載logger中間件來禁止對靜態資源請求進行日志記錄

app.use(express.static(__dirname+"/public"));
app.use(logger());

從多個目錄中提供靜態資源,但是"/public"目錄更有優先權

app.use(express.static(__dirname+"/public"));
app.use(express.static(__dirname+"/files"));
app.use(express.static(__dirname+"/uploads"));

三、Request

req對象代表HTTP請求并且對于請求的查詢字符串有屬性,parameter、body、HTTP headers等,按照慣例,在這份文檔中用req代替這個對象(HTTP response是res),但是它真正的名字是由工作的回調函數中的參數決定的。

例如:

app.get("/user/:id",function(req,res){
    res.send("user "+req.params.id);
});

但是你也可以像這樣:

app.get("/user/:id",function(request,response){
    response.send("user "+request.params.id);
})
屬性

在Express4中,req.files默認不在req對象中。在req.files對象中獲取上傳的文件,通過大量處理的中間件如busboymulterformidablemultipartyconnect-multiparty或者pez

req.app

這個屬性持有一個正在使用中間件的Express應用程序的實例。

如果你創建一個模塊僅僅是為了導出作為中間件在主要文件中使用,中間件就可以通過req.app訪問express。
例如:

//index.js
app.get("/viewdirectory",require("./mymiddleware.js"));
//mymiddleware.js
module.exports=function(req,res){
    res.send("The views directory is" + req.app.get("views"));
});

req.baseUrl

一個路由器掛載的路徑,例如:

var greet=express.Route();

greet.get("/jp",function(req,res){
    console.logd(req.baseUrl);
    res.send("Konichiwa!");
});

app.use("/greet",greet);//load the router on "/greet"

即使你使用路徑模式或者是一組路徑模式來加載路由器,baseUrl屬性返回的是匹配的字符串,不是模式,在下面的例子中,greet路由器掛載在了兩個路徑模式中

app.use(["/gre+t","/hel{2}o"],greet],greet);//load the router on "/gre+t" and "/hel{2}o"

當請求是/greet/jp,req.baseUrl就是"/greet",當請求是/hello/jp,req.baseUrl就是"/hello"。
req.baseUrl很像app對象的mountpath屬性,除了app.mountpath返回的是匹配的路徑屬性。

req.body

包含在請求體中提交的鍵值對數據,默認值是undefined,當你使用body-parsing中間件,像bosy-parsermulter,就會取出這些鍵值對。

下面這個例子展示了如何使用bosy-parser中間件解析req.body。

var app=require("express");
var bodyParser=require("body-parser");
var multer=require("multer");

app.use(bodyParser.json());//for parsing application/json
app.use(badyParser.urlencoded({extened:true}));//for parsing application/x-www-form-urlencoded
app.use(multer());//for parsing multipart/form-data

app.post("/",function(req,res){
    console.log(req.body);
    res.json(req.bosy);
})

req.cookies

當使用cookie-parser中間件,這個屬性就是包含請求發送的cookies的對象,如果請求中沒有cookies,它默認就是{}

//Cookie:name=tj
req.cookies.name
//=> "tj"

獲取更多信息、問題、關注,請看cookie-parser

req.fresh
表明請求是否是"fresh",它是req.stale的相反面。

如果一個cache-control沒有一個no-cache指令,req.fresh是true,并且下面的情況也是true

  • if-modidied-since請求頭指定了并且last-modified請求頭相等于或者早于modified請求頭

  • if-none-match請求頭是*

  • if-none-match請求頭在解析成它的指令后,沒有匹配etag響應頭

req.fresh
//=>true

獲取更多信息、問題、關注,請看fresh

req.hostname

包含從"Host"HTTP頭獲取的主機名

//Host:"example.com:3000"
req.hostname
//=> "example.com"

req.ip

請求的IP地址。

如果trust proxy設置的是enabled,返回的就是上游地址;獲取更多信息,請看Express behind proxies

req.ip
//=>"127.0.0.1"

req.ips

當trust proxy設置為true是,這個屬性包含在“X-Forwarded-For”請求頭中的ip地址數組,否則它包含的就是一個空數組。

例如,如果“X-Forwarded-For”是“client,proxy1,proxy2”,req.ips就是["client","proxy1","proxy2"],proxy2就是最下游的ip

獲取更多關于trust proxy的設置,請看app.set

req.originalUrl

req.url不是一個原生的Express屬性,他是從Node的http模塊中繼承的。

這個屬性很像req.url,但是它保留了原始的請求URL,允許你為了路由目的自由重寫req.url。例如,app.use的“mounting”特性會重寫req.url去脫離掛載點

//GET /search?q=something
req.originalUrl
//=>"/search?q=something"

req.params

一個包含匹配路由名為“parameters”屬性的對象,例如,如果你有路由為“/user/:name”,name屬性存在于req.params.name中,這個對象默認是{}

//GET /USER/tj
req.params.name
//=>"tj"

當你使用一個正則表達式定義路由時,用req.params[n]會提供capture groups,當n是第n個capture group時,這個規則適用于沒有命名的字符串路徑比如/file/*

//GET /file/javascript/jquery.js
req.params[0]
//=>"javascript/jquery.js"

req.path

包含請求URL的路徑

//example.com/users?sort=desc
req.path
//=>"/users"

當從一個中間件中調用的時候,req.path不包含加載點,獲取更多詳細信息請看app.user()

req.protocol

請求協議的字符串。當通過TLS(安全傳輸層協議)請求時是“http”或者是“https”。當“trust proxy”設置為trusts the socket address,“X-Forwarded-Proto”頭(http或者https)區域的值將會被信任如果存在的話。

req.protocol
//=>"http"

req.query
一個包含在路由中每個查詢參數屬性的對象,如果沒有查詢字符串,這就是一個空對象{}

//GET /search?q=tobi+ferret
req.query.q
//=>"tobi ferret"

//GET /shoes?order=desc&shoe[color]=blue&shoe[type]=converse
req.query.order
//=>"desc"

req.query.shoe.color
//=>"blue"

req.query.shoe.type
//=>"converse"

req.route

目前匹配的路由的字符串,例如

app.get("/user/:id?",function(req,res){
    console.log(req.route);
    res.send("GET");
})

以上代碼輸出:

{ path: '/user/:id?', 
  stack: 
    [ { handle: [Function: userIdHandler], 
        name: 'userIdHandler', 
        params: undefined, 
        path: undefined,
        keys: [], 
        regexp: /^\/?$/i, 
        method: 'get' } ], 
  methods: { get: true } }

req.secure

如果一個TLS連接已經建立這是布爾值true,相等于:

"https"==req.protocol

req.signedCookies

當使用cooki-parser中間件時,這個屬性包含請求發送的已經簽署的cookies,簽署的cookies在一個表明開發者意圖的對象。否則,惡意攻擊很容易被置于req.cookie(很容易欺騙)中。簽署一個cookie時并不是使它隱藏或者加密,僅僅是防止篡改(因為簽署的密碼是私有的)。如果發送的是一個沒有簽署的cookies,這個屬性默認就是{}

//Cookie:user=tobi.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
req.signedCookies.user
//=>"tobi"

獲取更多信息、問題、關注,請看cooki-parser

req.stale

表明請求是否是"stale",它是req.stale的相反面。獲取更多信息,請看req.fresh

req.stale
//=>true

req.subdomains

請求中域名的子域名組成的數組

//Host:"tobi.ferrets.example.com"
req.subdomains
//=>["ferrets","tobi"]

req.xhr

如果請求“X-Requested-With”頭字段是“XMLHttpRequest”,表明請求是由客戶端發送的例如jQuery

req.xhr
//=>true
方法

req.accepts(types)

基于請求的Accept HTTP頭字段,檢查指定的內容類型是否可接受。這個方法返回最佳匹配或者如果指定的類型不可接受,則返回undefined(在這種情況下,應用程序響應為406"Not Acceptable")。

type值可以是一個單獨的MIME類型的字符串(比如"application/json"),也可以是一個拓展名比如"json",一個逗號分隔的列表,或者一個數組。對于一個列表或是數組,這個方法返回最佳匹配(如果有的話)。

//Accept:text/html
req.accepts("html");
//=>"html"

//Accept:text/*,application/json
req.accepts("html");
//=>"html"
req.accepts("text/html");
//=>"text/html"
req.accepts(["json","text"]);
//=>"json"
req.accepts("application/json");
//=>"application/json"

//Accept:text/*;q=.5,application/json
req.accepts("image/png");
req.accept("png");
//=>undefined

//Accept:text/*;q=.5,application/json
req.accepts(["html","json"]);
//=>"json"

獲取更多信息,或者你有問題或者關注,請看accepts

req.acceptsCharsets(charset[,...])

基于請求的“Accept-Charset” HTTP頭字段,返回指定字符集的最初受理的字符。如果指定的字符沒有可接受的,則返回false。

獲取更多信息,或者你有問題或者關注,請看accepts

req.acceptsEncodings(encoding[,...])

基于請求的“Accept-Charset” HTTP頭字段,返回指定編碼的最初受理的編碼。如果指定的編碼沒有可接受的,就返回false。

獲取更多信息,或者你有問題或者關注,請看accepts

req.acceptsLanguages(lang[,...])

基于請求的“Accept-Charset” HTTP頭字段,返回指定語言的最初受理的語言。如果指定的語言沒有可接受的,就返回false。

獲取更多信息,或者你有問題或者關注,請看accepts

req.get(field)

返回指定的HTTP請求頭字段(不區分大小寫)。Referrer和Referer字符是相同的。

req.get("Content-Type");
//=>"text/plain"

req.get("content-type");
//=>"text/plain"

req.get("Something");
//=>undefined

這個方法的別名是req.header(field)。

req.is(type)

如果即將到來的請求的“Content-Type”HTTP頭字段與指定的MIME類型匹配,則返回true,否則返回false

//With Content-Type:text/html;charset=utf-8
req.is("html");
req.is("text/html");
req.is("text/*");
//=>true

//When Content-Type is application/json
req.is("json");
req.is("application/json");
req.is("application/*");
//=>true

req.is("html");
//=>false

獲取更多信息,或者你有問題或者關注,請看type-is

req.param(name[,defaultValue])

已經過時,請使用req.params,req.body或者req.query代替。

返回name參數的現有值。

//?name=tobi
req.param("name")
//=>"tobi"

//POST name=tobi
req.param("name")
//=>"tobi"

// /user/tobi for /user/:name
req.param("name")
//=>"tobi"

查找按以下順序進行:

  • req.params

  • rea.body

  • req.query

可選:如果參數在任何的請求對象中沒有找到,你可以為其指定一個默認值。

直接訪問應該使用req.body,req.params和req.query。

Body-parsing中間件應該為req.param加載以正常工作,查看req.body獲取更詳細的信息。

四、Response

當收到一個請求時,res對象代表Express應用程序發送的HTTP響應。

按照慣例,在這份文檔中用res代替這個對象(HTTP request是req),但是它真正的名字是由工作的回調函數中的參數決定的。

例如:

app.get("/user/:id",function(req,res){
    res.send("user "+req.params.id);
});

但是你也可以像這樣:

app.get("/user/:id",function(request,response){
    response.send("user "+ request.params.id);
});  
屬性

res.app

這個屬性持有一個正在使用中間件的Express應用程序的實例。

res.app和request對象中的req.app屬性是一樣的。

res.headersSent

一個布爾值表明應用程序是否發送HTTP響應頭

app.get("/",function(req,res){
    console.log(res.headerSent);//false
    res.send("OK");
    console.log(res.headersSent);//true
})

res.locals

一個包含請求作用域的響應的本地變量,因此僅適用于在該請求/響應周期(如果存在)的渲染視圖中。否則,這個屬性和app.locals相同。

這個屬性對于暴露請求級的信息很有用,比如請求的路徑名、認證的用戶、用戶的設置等。

aap.use(function(req.res){
    res.locals.user=req.user;
    res.locals.authenticated=!req.user.anonymous;
    next();
})
方法

res.append(field[,value])

res.append()在Express v4.11.0版本之后才支持。

如果響應頭還沒有設置好,給HTTP響應頭字段設置指定的值,它以特定的值創建頭部。value可以是一個字符串或者是數組。

注意:在res.append()之后調用res.set()會重置之前設置好的頭部值。

res.append("Link",["<http://localhost/>","<http:/localhost:3000>"]);
res.append("Set-Cookie","foo=bar;Path=/;HttpOnly");
res.append("Warning","199 Miscellaneous warning");

res.attachment([filename])

將HTTP響應頭字段"Content-Disposition"為"attachment".如果filename已經給了,并基于后綴名通過res.type()設置了Content-Type,設置了Content-Disposition“filename=”parameter

res.attachment();
//Content-Disposition:attachment

res.attachment("path/to/logo.png");
//Content-Disposition:attachment;filename="logo.png"
//Content-Type:image/png

res.cookie(name,value[,options])

設置cookie的鍵值對,value參數可以是一個字符串或者是一個轉化為JSON的對象。
options參數是一個可以具有以下屬性的對象。

所有res.cookie()都沒有用提供的選項設置HTTP Set-Cookie頭部。任何選項未指定默認為RFC6265規定的值。

例如:

res.cookie("name","tobi",{damin:".example.com",path:"/admin",secure:true});
res.cookie("rememberme","1",{expires:new Date(Date.now()+900000),httpOnly;true});

maxAge選項是一個設置到期時間的簡便選項,這個到期時間是相對于現在以毫秒為單位的時間。下面的例子相當于上面的第二個例子

res.cookie("rememberme","1",{maxAge:900000,httpOnly:true});

你可以傳遞一個對象給value參數,它會被序列化為JSON然后被bodyParser()中間件解析。

res.cookie("cart",{items:[1,2,3]});
res.cookie("cart",{items:[1,2,3]},{maxAge:900000});

當使用cookie-parser中間件的時候,這個方法也支持簽署的cookie。僅僅需要吧signed選項設置為true,然后res.cookie()會傳遞密碼給cookieParser(secret)去簽署這個值

res.cookie("name","tobi",{signed:true});

然后可以通過req.signedCookie對象訪問這個值。

res.clearCookie(name[,options])

通過那么清除指定的cookie,獲取options對象更詳細的內容,請看res.cookie()。

res.cookie("name","tobi",{path:"/admin"});
res.clearCookie("name",{path:"/admin"});

res.download(path[,filename][,fn])

將path路徑上的文件傳遞為"attachment",一般情況下,瀏覽器會提示用戶下載。默認情況下,Content-Disposition頭“filename=”參數是path(這一般會在瀏覽器的彈出框中出現)。通過filename參數覆蓋這個默認值。

當有錯誤出現或者傳遞完成時,這個方法會調用可選的回調函數fn,這方法用res.sendFile()傳遞文件

res.download("/report-12345.pdf");

res.download("/report-12345.pdf","report.pdf");

res.download("/report-12345.pdf","report.pdf",function(err){
    if(err){
        //Handle error, but keep in mind the response may be partially-sent
        //so check res.headersSent
    }else{
        //decrement a download credit, etc.
    }
});

res.end([data][,encoding])

終止響應進程。這個方法實際上來自于Node內核,具體在response.end() method of http.ServerResponse.
沒有數據用這個方法可以迅速終止響應。如果你想要通過數據響應,用其他方法如res.send()和res.json()代替。

res.end();
res.status(404).end();

res.format(object)

在請求體中對Accept HTTP 頭執行content-negotiation,如果存在的話。它用res.accepts()對請求選擇一個處理方法,通過值的順序基于可接受類型。如果頭部沒有指定,第一個回調函數會被調用。如果沒有找到匹配的,服務器返回響應406“Not Acceptable”,或者調用默認的回調函數。
當一個回調函數已經選擇了,Content-Type響應頭就已經設置了。但是你可能會在回調函數中用方法比如res.set()或者res.type()。
當Accept頭字段設置為"application/json"或者"/json"時,下面的例子會響應{"message":"hey"}(如果是"/*",響應會是"hey")。

res.format({
    "text/plain":function(){
        res.send("hey");
    },
    "text/html":function(){
        res.send("<p>hey</p>");
    },
    "applocation/json":function(){
        res.send({message:"hey"});
    },
    "default":function(){
        //log the request and respond with 406
        res.status(406).send("Not Acceptable");
    }
});

除了規范化的MIME類型,你也可以使用拓展名:

res.format({
    text:function(){
        res.send("hey");
    },

    html:function(){
        res.send("<p>hey</p>")
    },

    json:function(){
        res.send({message:"hey"});
    }
});

res.get(field)

根據field返回指定的HTTP響應頭,匹配時忽略大小寫

res.get("Content-Type");
//=>"text/plain"

res.json([body])

發送一個JSON響應。這個方法與res.send()方法使用對象或者數組作為參數是相同的。但是,你可以用這個方法將其他值轉化為JSON,比如null和undefined(雖然這些從技術上來說不是有效的JSON)

res.json(null);
res.json({user:"tobi"});
res.status(500).json({error:"message"})

res.jsonp([body])

發送帶有JSONP支持的JSON響應。這個方法和res.json()方法是相同的。除了它采用JSONP回調支持。

res.jsonp(null)
//=>null

res.jsonp({user:"tobi"})
//=>{"user":"tobi"}

res.status(500).jsonp({error:"message"})
//=>{"error":"message"}

默認情況下,JSONP回調名字僅僅是callback,通過jsonp callback name設置覆蓋設置。

下面是使用相同的代碼的JSONP響應的例子:

//?callback=foo
res.jsonp({user:"tobi"})
//=>foo({"user":"tobi"})

app.set("jsonp callback name","cb");

//?cb=foo
res.status(500).jsonp({error:"message"})
//=>foo({"error":"message"})

res.links(links)

連接提供的links作為參數的屬性填入響應的Link HTTP頭字段。

res.links({
    next:"http://api.example.com/users?page=2",
    last:"http://api.example.com/users?page=5"
})

輸出:

Link:<http://api.example.com/users?page=2>;rel="next",
          <http://api.example.com/user?page=5>;rel="last"

res.location(path)

根據指定的path參數響應的Location HTTP響應頭。

res.location("/foo/bar");
res.location("htttp://example.com");
res.location("back");

path值"back"有特殊的含義,它代指請求中的Referer請求頭中指定的URL。如果Referer頭沒有指定,它指"/"。

沒有任何驗證或者操作,Express在Location頭傳遞指定的URL字符串給瀏覽器,除了back情況。

瀏覽器從當前的URL或者引用的URL中派生出將要前往的URL,URL在Location頭中指定,因此用戶會重定向。

res.redirect([status,]path)

根據指定的paht進行重定向和指定的HTTP狀態碼。如果你沒有指定status,狀態碼就是默認的302Found

res.redirect("/foo/bar");
res.redirect("http://example.com");
res.redirect(301,"http://example.com");
res.redirect("../login");

重定向可以是一個完整的URL重定向值一個不同的網站

res.resirect("http://google.com");

重定向可以是主機名的根目錄的相對路徑。例如,如果應用程序在<code>http://example.com/admin/post/new</code>下面的例子會重定向至<code>http://example.com/admin</code>

res.redirect("/admin");

重定向也可以是當前URL的相對路徑,例如從路徑<code>http://example.com/blog/admin/</code>(注意斜杠),下面的例子會重定向至<code>http://example.com/blog/admin/post/new</code>

res.resdirect("post/new");

從<code>http://example.com/blog/admin</code>(沒有斜杠)重定向post/new會重定向至<code>http://example.com/blog/post/new</code>。

如果你發現上面的有些疑惑,就想想目錄中的分隔(通過斜杠),這就會清楚。

相對路徑重定向也有可能。如果你在<code>http://example.com/admin/post/new</code>,下面的例子就會重定向至<code>http://example.com/admin/post</code>

res.resirect("..");

back重定向至之前的rederer,當引用不見之時,默認為/

res.redirect("back");

res.render(view[,locals][,callback])

渲染一個視圖并且將渲染好的HTML發送給客戶端,可選的參數:

  • locals,一個對象,在本地定義的為視圖使用的變量作為這個對象的屬性

  • callback一個回調函數,如果提供,這個函數返回可能的錯誤和渲染的字符串,但是不自動執行響應。當一個錯誤出翔,這個方法內部調用next(err)。

本地變量cache允許視圖緩存。把它設置為true,在開發環境中允許視圖緩存,視圖緩存在生產環境中默認使用。

//send the rendered view to the client
res.render("index");

//if a callback is specified, the rendered HTMLstring has to be sent explicitly
res.render("index",function(err,html){
    res.send("html");
});

//pass a local variable to the view
res.render("user",{name:"Tobi"},function(err,html){
    //...
});

res.send([body])

發送HTTP響應。

這個body對象可以是一個Buffer對象,一個字符串,一個對象,一個數組。例如:

res.send(new Buffer("whoop"));
res.sendf({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:});

這個方法可以執行很多有用的簡單不需要流的響應任務:例如,它可以自動指定Content-Length HTTP響應頭字段(除非提前定義好了),提供自動的HEAD和高速緩存支持。

當參數是一個Buffer對象時,這個方法設置Content-Type響應頭字段為"application/octet-stream",除非像下面一樣提前定義好:

res.set("Content-Type","text/html");
res.send(new Buffer("<p>some html</p>"));

當參數是字符串時,這個方法設置"Content-Type"為"text/html":

res.send("<p>some html</p>");

當參數是一個數組或者是對象時,Express響應JSON格式:

res.send({user:"tobi"});
res.send([1,2,3]);

res.sendFile(path[,options][,fn]])

res.sendFile()在Express v4.8.0及之后版本支持。

傳送文件給給定的path,基于文件名的后綴名設置Content-Type HTTP響應頭。除非root選項在可選的對象中設置,path必須是文件的絕對路徑。

options對象的詳細信息在下面的表格中列出:

當傳輸完成或者出現錯誤的時候,這個方法會調用回調函數fn(err)。如果這個回調函數指定并且有錯誤發生,這個回調函數必需明確地指出解決方法,要么是終止request-response循環。要么把控制權傳遞給下一個路由。

下面是一個使用res.sendFile并包含所有參數的例子:

app.get("/file/:name",function(req,res,,next){
    
    var options={
        root:__dirname+"/public/",
        dotfiles:"deny",
        headers:{
            "x-timestamp":Date.now(),
            "x-sent":true
        }
    };

    var filename=req.params.name;
    res.sendFile(fileName,options,function(err){
        if(err){
            console.log(err);
            res.status(err.status).end();
        }
        else{
            console.log("Sent: ",fileName);
        }
    });

})

res.sendFile為文件服務提供了很詳細的支持,下面的例子就像圖示一樣:

app.get("/user/:uid/photo/:file",function(req,res){
    var uid=req.params.uid,
          file=req.params.file;
    req.user.mayViewFilesFrom(uid,function(yes){
        if(yes){
            res.sendFile("/uploads/"+uid+"/"+file);
        }else{
            res.status(403).send("Sorry!you can't see that.");
        }
    });
})

獲取更多信息,或者你有問題和關注,請看send

res.sendStatus(statusCode)

給statusCode設置HTTP狀態碼,并且發送其字符串代表響應主體。

res.sendStatus(200);//equivalent to res.status(200).send("OK")
res.sendStatus(403);//equivalent to res.status(403).send("Forbidden")
res.sendStatus(404);//equivalent to res.status(404).send("Not found")
res.sendStatus(500);//equivalent to res.status(500).send("Internal Server Error")

如果指定了一個不支持的狀態碼,這個狀態碼仍然會設置在statusCode中并且這個狀態碼以字符串形式發送給響應主體。

res.sendStatus(2000);//equivalent to res.status(2000).send("2000")

更多關于HTTP Status Codes

res.set(field[,value])

給HTPP響應頭field設置為value值。一次性設置多個值,請傳遞一個對象做參數。

res.set("Content-Type","text/plain");

res.set({
    "Content-Type":"text/plain",
    "content-Length":"123",
    "ETag":"12345"
})

別名是res.header(field[,value])

res.status(code)

用這個方法設置HTTP響應狀態碼,這是一個可以鏈式調用的Node的response.statusCode的別名。

res.status(403).end();
res.status(400).send("Bad Request");
res.status(404).sendFile("/absolute/path/to/404.png");

res.type(type)

設置指定MIME類型的Content-Type HTTP響應頭。如果type中包含"/"字符,則其設置Content-Type為type

res.type(".html");        //=>"text/html"
res.type("html");         //=>"text/html"
res.type("json");          //=>"application/json"
res.type("application/json")        //"application/sjon"
res.type("png");          //=>image/png

res.vary(field)

添加響應字段,如果這個字段不存在的話

res.vary("User-Agent").render("docs");

Router

一個router是一個中間件和路由器的獨立實例。

你可以把它想象成一個迷你的應用程序,僅僅能夠執行中間件和路由方法。每一個Express應用程序都有一個內置的app路由器。

一個路由器就像一個中間件一樣,你可以把它作為app.use()的參數或者是另一個路由器use()方法的參數。
頂級的Express對象有一個Router()方法用來創建router對象。

Router([options])

像下面一樣創建一個新的路由器:

var router=express.Router([options]);

可選的options參數指定路由器的行為:

你可以像應用程序一樣給路由器添加中間件和HTTP方法(比如:get,put,post等等)

//invoked for any requests passed to this router
router.use(function(req,res,next){
    //.. some logic here .. like any other middleware
    next();
}):

//will handle any request that ends in /events
//depends on where the router is "use()"
router.get("/events",function(req,res,next){
    // ..
});

然后你可以用這種方法給特殊的root URL添加路由器,將其分成文件或者mini-app。

//only requests to /calendar/* will be sent to our "router"
app.use("/calendar",router)
方法

router.all(path,[callback,...]callback)

這個方法就像router.METHOD()方法,除了它匹配所有的HTTP方法。

對于特定的路徑前綴或者是任意匹配映射全局邏輯。例如,你把下面的內容放在所有路由定義的前面,它要求所有從這個點開始的路由都需要加載認證和自動加載一個用戶,請記住這些回調函數并不一點是終點,loadUser可以像一個任務一樣,然后使用next()方法繼續匹配接下來的路由。

router.all("*",requireAuthentication,loadUser);

相等于:

router.all("*",requireAuthentication);
router.all("*",loadUser);

另一個例子就是使用全局函數,這個例子很像前面的,但是這個把路徑限制了以"/api"開頭的路徑

router.all("/api/*",requireAuthentication);

router,METHOD(path,[callback,...]callback)

router.METHOD()方法在Express中提供路由函數,METHOD是一個HTTP方法,比如GET,PUT,POST的小寫版本等,因此實際的方法是router.get()、router.post()、router.put()等。

你可以提供很多的回調函數,就像中間件一樣,除了這些回調可以調用next("route")來繞過接下來的路由回調,你可以用這種機制給一個路由設置一些前提條件,如果當前路由并不能滿足條件,你可以將控制權傳遞給接下來的路由。
下面的代碼片段展示了最簡單的最可能的路由定義。Express內部將路徑字符串轉化為正則表達式,匹配即將到來的請求。執行這些匹配的時候,查詢字符串不考慮,例如,“GET /”會匹配下面的路由,也會匹配“GET /?name=tobi”。

router.get("/",function(req,res){
    res.send("hello world");
})

你可以使用正則表達式,這在你有特定的限制的時候很有用,例如,下面代碼會匹配"GET /commits/71dbb9c",也會匹配"GET /commits/71dbb9c..4c084f9"。

router.get(/^\/commit\/(\w+)(?:\.\.(\w+))?$/,function(req,res){
    var from=req.params[0];
    var to=req.params[1]  ||  "HEAD";
    res.send("commit range "+  from +".."+to);
});

router.param([name,]callback)

為路由參數添加一個觸發回調函數,name是一個參數或者是一個name組成的數組,回調函數是一個方法。回調函數的參數是requset對象,response對象,next中間件和按照順序的name的值。如果name是一個數組,回調函數觸發器按照這個數組中每個參數的聲明順序進行掛載。此外,除數組中最后一個參數外,在回調函數中調用next會調用數組中下一個參數的回調函數,對于數組中的最后一個參數, 調用next會調用這個路由正在處理的下一個中間件,就像它是一個string一樣例如,當:user在一個路由路徑中,你可能需要匹配用戶加載邏輯去自動提供req.user的路徑或者展示參數輸入驗證。

router.param("user",function(req,res,next,id){
    //try to get the user details from the User model and attach it to request object
    User.find(id, function(err,user){
        if(err){
            next(err);
        }else if(user){
            req.user=user;
            next();
        }else{
            next(new Error("failed to load user"));
        }
    });
}): 

回調函數是他們本地定義的路由器,他們不是繼承自掛接的app或者是路由器,因此,定義在app中的param回調函數只會被定義在app路由器中定義的參數觸發。

所有的param回調函數都會在其他出現param的路由處理之前調用,并且再一次請求和響應循環中,他們只會被調用一次,即使這個參數匹配在很多路由中,就像下面的例子一樣:

router.param("id",function(req,res,next,id){
    console.log("CALLED ONLY ONCE");
    next();
});

app.get("/user/:id",function(req,res,next){
    console.log("although this matches");
    next();
});

app.get("/user/:id",function(req,res){
    console.log("and this matches too");
    res.end();
})

On GET /user/42/3,打印出以下內容:

CALLED ONLY ONCE
although this matches
and this matches too

router.route(path)

返回一個單獨路由器的實例,然后你可以用它和可選的中間件來處理HTTP操作。用app.route()避免重復的路由名字(和錯字錯誤)。

以上面的例子為基礎,下面的代碼展示了如何用router.route()指定不一樣的HTTP處理方法。

var router=express.Router();

router.param("user_id",function(req,res,next,id){
    //sample user, would actually fetch from DB, etc...
    req.user={
        id:id,
        name:"TJ"
     };
      next();
});

router.route("/users/:user_id").all(function(req,res,next){
    //runs for all HTTP verbs first
    //think o it as route specific middleware!
    next();
}).get(function(req,res,next){
    res.json(req.user);
}).put(function(req,res,next){
    //just an example of maybe updating the user
    req.user.name=req.params.name;
    // save user ... etc
    res.json(req.user);
}).post(function(req,res,next){
    next(new Error("not implemented"));
}).delete(function(req,res,next){
    next(new Error("not implemented"));
})

這個方法重新使用單路徑"/user/:user_id"并且添加了多種HTTP處理方法。

router.use([path],[function,...]function)

使用給定的中間件function,給可選的路徑path掛載,路徑默認為"/"

這個方法像app.use(),一個簡單的例子和使用例子如下描述,請看app.use()獲取更多信息。

中間件就像一個垂直的水管,請求在你定義的第一個中間件開始,在往下工作匹配每一個中間件堆棧。

var express=require("express");
var app=express();
var router=express.Router();

//simple logger for this router's requests
//all requests to this router will first hit this middleware
router.use(function(req,res,next){
    console.log("%s %s %s",req.method,req.url,req.path);
    next();
});

//this will only be invoked if the path starts with /bar from the mount point
router.use("/bar",function(req,res,next){
    // ... maybe some additional /bar logging ...
    next();
});

//always invoked
router.use(fnction(req,res,next){
    res.send("Hello World");
});

app.use("/foo",router);
app.listen(3000);

mount路徑被剝離,在中間件函數中不可見。這個的主要影響是加載中間件或許不需要更改代碼操作,而不需管路徑的前綴。

用router.use()定義中間件的順序很重要,他們是按順序調用的,因此順序決定了優先權。例如,通常logger是你會使用的第一個中間件,所以每一個請求都有記錄。

var logger=require("morgan");

router.use(logger());
router.use(express.static(__dirname+"/public"));
router.use(function(req,res){
    res.send('Hello");
});

現在設想你想要忽略對靜態文件的記錄,但是繼續記錄在logger()之后定義的路由和中間件,你僅僅需要把static()放在上面:

router.use(express.static(__dirname+"/public"));
router.use(logger());
router.use(function(req.res){
    res.send("Hello");
});

另一個具體的例子就是從很多目錄中提供文件服務,給"./oublic"目錄高于其他目錄的優先權。

app.use(express.static(__dirname_"/public"));
app.use(express.static(__dirname_"/files"));
app.use(express.static(__dirname_"/uploads"));

router.use()方法同樣支持已經命名的參數,所以你的其他路由器可以從之前會用命名的參數加載過的路由中獲取便利。

最后是一個廣告貼,最近新開了一個分享技術的公眾號,歡迎大家關注??

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容