Express4.x之API:express
- express()表达式
- express的方法
- express功能分析
一、express()表达式
创建Express应用程序。express()函数是express模块导出的顶级函数。(相当于HTTP.createServer())
let express = require("express");
let app = express();
这个表达会生成一个Application对象,也就是示例中的app,Express框架构建的服务就是由这个对象来管理网络请求与响应。关于Application的具体操作及API在博客的第三部分,在express上还有还有一些静态方法,下面进入第二部分express方法的解析。
二、express的方法
2.1express.json([options]):是Express种的內置中间件功能,它使用body解析器解析请求带有JSON格式的报文主体。
在node原生中获取post请求的请求数据是通过request上的data事件来获取: request.on("data",function(data){console.log(data);}) ,在express中可以使用express.json()引用中间件来处理请求数据,处理后的数据会交给request.body缓存。具体使用如下:
在默认情况下,我们使用 req.body获取到的内容为空对象{},这里需要使用一个中间件body-parser
来解析传入的请求主体:
npm install body-parser express --save
创建server.js
1 let express = require("express"); 2 let bodyParser = require('body-parser'); 3 4 let app = express(); 5 6 //基于body-parser中间件注册解析post请求主体中的数据 7 //根据不同的Content-Type分别有以下两种配置 8 app.use(bodyParser.urlencoded());//解析Content-Type为:application/x-www-form-urlencoded的配置 9 app.use(bodyParser.json());//解析Content-Type为:application/json的配置 10 11 app.post("/csJSON",csJSONFun);//配置访问路由,调用csJSONFun处理请求 12 13 app.listen(12306);//配置服务端口 14 15 //将请求的数据(body-parser中间件处理后交给request.body的数据)再发送回客户端 16 function csJSONFun(request,response){ 17 console.log(request.body); 18 response.writeHead(200); 19 response.write(JSON.stringify(request.body)); 20 response.end(); 21 }
客户端测试代码:
1 urlAjaxFun(function(data){ 2 console.log(JSON.parse(data));//{{"APP":"express","text":"cs"}: ""} 3 }); 4 bodyAjaxFun(function(data){ 5 console.log(JSON.parse(data));//{APP: "express", text: "cs"} 6 }); 7 8 function urlAjaxFun(callback){ 9 let xhr = new XMLHttpRequest(); 10 let data = {APP:'express',text:"cs"} 11 xhr.open("POST","/csJSON",true); 12 xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded'); 13 xhr.send(JSON.stringify(data)); 14 xhr.onreadystatechange = function(){ 15 // 监听到readystate=4时 16 // 解析服务器返回的responseText数据 17 if(xhr["readyState"] === 4){ 18 //判断响应状态是否为200--表示请求成功响应 19 if(xhr["status"] === 200){ 20 callback(xhr["responseText"]); 21 } 22 } 23 } 24 } 25 26 function bodyAjaxFun(callback){ 27 let xhr = new XMLHttpRequest(); 28 let data = {APP:'express',text:"cs"} 29 xhr.open("POST","/csJSON",true); 30 xhr.setRequestHeader('Content-type','application/json'); 31 xhr.send(JSON.stringify(data)); 32 xhr.onreadystatechange = function(){ 33 // 监听到readystate=4时 34 // 解析服务器返回的responseText数据 35 if(xhr["readyState"] === 4){ 36 //判断响应状态是否为200--表示请求成功响应 37 if(xhr["status"] === 200){ 38 callback(xhr["responseText"]); 39 } 40 } 41 } 42 }
express.json([options])的options参数对象属性:
Property(属性) | Description(描述) | Type(类型) | Default(默认值) |
inflate | 是否启用或禁用压缩实体,禁用时,压缩的实体将被拒绝解析,request.body为空对象{}。 | Boolean | true |
limit | 限定解析的请求正文的大小,当超过限定值时拒绝解析实体。建议参数格式:字节数+单位 | 混合(一般使用字符串) | "100kb" |
reviver | 这个参数实际上是JSON.parse(text,[reviver])中的reviver可选参数,一般是一个函数(k,v)=>{}将解析出来的对象采用键值方式传入这个函数,在这个函数内修改值会作为JSON.parse()解析JSON数据最后的数据值。详细可参考:MDN文档 JSON.parse() | Function | null |
strict | 启用或禁用仅接收数组和对象;禁用时可以接收任何参数类型的JSON,比如字符串。默认禁用,测试当接收到字符串的JSON时抛出错误。 | Boolean | true |
type | 用于确定中间件将解析的媒体类型。这用于确定中间件将解析的媒体类型。此选项可以是字符串,字符串数组或函数。如果不是函数,则将type 选项直接传递到type-is库,该名称可以是扩展名(如json ),MIME类型(如application/json )或带有通配符的MIME类型(如*/* 或*/json )。如果是函数,则将type 选项称为as fn(req) ,如果请求返回真实值,则将解析请求。 |
混合(一般使用字符串) | "application/json" |
verify | 如果提供此选项,则称为verify(req, res, buf, encoding) ,其中buf 是Buffer 原始请求正文的,encoding 是请求的编码。抛出错误可以中止解析。 |
Function | undefined |
2.2express.static(root,[options]):这是Express中的内置中间件功能。它用来配置静态文件资源的根目录,配合request.url给请求响应相对应的资源。
参数:root,用来指定服务提供的静态资源的根目录。
参数:options,可选的object类型参数,其属性用来指定express如何处理静态资源的请求,及一些响应静态资源的行为(主要体现在响应报文头的相关内容上)。
express.static()配合get请求应用,当请求资源为空时会默认定义到index.html上(如:url:127.0.0.1:12306),如果静态资源根目录下没有请求的资源会相应404。
1 //工作区间 2 page--静态资源根目录 3 --index.html 4 --login.html 5 index.js 6 7 let express=require("express"); 8 let app = express(); 9 app.use(express.static("page")); 10 app.listen(12306);
本地测试:
127.0.0.1:12306 ----响应index.html
127.0.0.1:12306/index.html ----响应index.html
127.0.0.1:12306/login.html ----响应login.html
127.0.0.1:12306/test.html ----响应404
express.static()的options参数:
Property(属性) | Description(描述) | Type(类型) | Default(默认值) |
dotfiles | 指定如何处理已"."开头的文件或目录,例如:请求url为"/.app/index.html"。处理方式有三种:允许(allow),对点文件没有特殊处理;拒绝(deny),拒绝对点文件的请求,响应403状态码,然后调用next();忽略(ignore),当点文件不存在的时候,响应404,然后调用next(). | String | ignore |
etag | 启用或禁用etag生成。注意express.static始终都会发送etag。启用与禁用实际是指是否开启通过标签验证缓存新鲜度。相关内容可以了解HTTP缓存机制 | Boolean | true |
extensions | 设置备用的文件扩展名,如果没有找到指定扩展名的文件,会使用备用的文件扩展名匹配静态资源并将第一个匹配到的文件响应给客户端。例如:['html','htm'] | Mixed | false |
fallthrough | 指定当客户端错误不能处理的请求时,如何处理。当设置为true时,将会继续调用next()继续处理这个请求,否则设置为false时,这个错误(即404是错误)会调用next(err)。 | boolean | true |
immutable | 是否启用Cache-Control相应头(这需要客户端支持),可以理解为是否开启http缓存,这还需要后面的maxAge属性配合设置缓存时间。 | boolean | true |
index | 设置默认的响应资源,比如本地测试时:127.0.0.1:12306没有指定请求文件,就会定位到这个设定的资源,并相应给客户端。 | Mixed | 'index.html' |
lastModified | 是否将Last-Modified首部设置为操作系统上文件的最后修改时间。这也是一个用于控制缓存的操作,详细了解:HTTP缓存机制 | Boolean | true |
maxAge | 用于设置响应报文中的Cache-Control首部的max-age属性(以毫秒为单位)。指定缓存多久时间。详细了解:HTTP缓存机制 | Number | 0 |
redirect | 当路径时目录名时(root),是否重定向到"/"。 | Boolean | true |
setHeaders | 这个属性用来设定响应报文的一些首部信息。详细参考后面的示例。 |
express.static()的options参数示例(来源官方文档):
1 var options = { 2 dotfiles: 'ignore', 3 etag: false, 4 extensions: ['htm', 'html'], 5 index: false, 6 maxAge: '1d', 7 redirect: false, 8 setHeaders: function (res, path, stat) { 9 res.set('x-timestamp', Date.now()) 10 } 11 } 12 13 app.use(express.static('public', options))
2.3express.urlencoded([options]):这是Express中的内置中间件功能。它使用urlencode的有效载荷来解析传入的请求,并且基于body-parser。
Property(属性) | Description(描述) | Type(类型) | Default(默认值) |
extended | 通过此选项,您可以在使用querystring库(when false)或使用qs库(when true)解析URL编码的数据之间进行选择。“扩展”语法允许将丰富的对象和数组编码为URL编码格式,从而使URL编码具有类似JSON的体验。有关更多信息,请参见qs库。 | Boolean | true |
inflate | 是否启用或禁用压缩实体,禁用时,压缩的实体将被拒绝解析,request.body为空对象{}。 | Boolean | true |
limit | 限定解析的请求正文的大小,当超过限定值时拒绝解析实体。建议参数格式:字节数+单位 | 混合(一般使用字符串) | '100kb' |
parameterLimit | 此选项控制URL编码数据中允许的最大参数数量。如果请求中包含的参数超出此值,则会引发错误。 | Number | 1000 |
type | 这用于确定中间件将解析的媒体类型。此选项可以是字符串,字符串数组或函数。如果不是函数,则将type选项直接传递给type-is库,该名称可以是扩展名(如urlencoded),MIME类型(如application/x-www-form-urlencoded)或带有通配符的MIME类型(如*/x-www-form-urlencoded)。如果是函数,则将type选项称为as fn(req),如果请求返回真实值,则将解析请求。 | 混合(一般使用字符串) | "application/x-www-form-urlencoded" |
verify | 如果提供此选项,则称为verify(req, res, buf, encoding),其中buf是Buffer原始请求正文的,encoding是请求的编码。抛出错误可以中止解析。 | Function | undefined |
创建服务server.js
1 let express = require("express"); 2 let app = express(); 3 let bodyParser = require('body-parser'); 4 5 function csJSONFun(request,response){ 6 console.log(request.query); 7 response.writeHead(200); 8 response.write(JSON.stringify(request.query)); 9 response.end(); 10 } 11 12 app.use(bodyParser.urlencoded({extended: false})); 13 app.use(bodyParser.json()); 14 //post请求与get请求如果在url中带有参数,可以直接通过request.query获取object类型的数据 15 app.post("/csJSON",csJSONFun); 16 app.get("/csJSON",csJSONFun); 17 18 app.listen(globalConfig["port"]);
客户端测试代码:
1 URLAjaxFunc(function (data) { 2 console.log(data); 3 }); 4 5 function URLAjaxFunc(callback){ 6 let xhr = new XMLHttpRequest(); 7 xhr.open('POST', 'csJSON?app=express&text=cs', true); 8 // xhr.open('GET', 'csJSON?app=express&text=cs', true); 9 xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded'); 10 xhr.send(); 11 xhr.onreadystatechange = function(){ 12 // 监听到readystate=4时 13 // 解析服务器返回的responseText数据 14 if(xhr["readyState"] === 4){ 15 //判断响应状态是否为200--表示请求成功响应 16 if(xhr["status"] === 200){ 17 callback(xhr["responseText"]); 18 } 19 } 20 } 21 }
2.4express.raw([options]):这是Express中的内置中间件功能。它将传入的请求有效内容解析为,Buffer
并基于 body-parser。
Property(属性) | Description(描述) | Type(类型) | Default(默认值) |
inflate | 是否启用或禁用压缩实体,禁用时,压缩的实体将被拒绝解析,request.body为空对象{}。 | Boolean | true |
limit | 限定解析的请求正文的大小,当超过限定值时拒绝解析实体。建议参数格式:字节数+单位 | 混合(一般使用字符串) | '100kb' |
type | 这用于确定中间件将解析的媒体类型。此选项可以是字符串,字符串数组或函数。如果不是函数,则将type选项直接传递给type-is库,该名称可以是扩展名(如urlencoded),MIME类型(如application/x-www-form-urlencoded)或带有通配符的MIME类型(如*/x-www-form-urlencoded)。如果是函数,则将type选项称为as fn(req),如果请求返回真实值,则将解析请求。 | 混合(一般使用字符串) | "application/x-www-form-urlencoded" |
verify | 如果提供此选项,则称为verify(req, res, buf, encoding),其中buf是Buffer原始请求正文的,encoding是请求的编码。抛出错误可以中止解析。 | Function | undefined |
创建一个server服务:
1 let express = require("express"); 2 let app = express(); 3 let bodyParser = require('body-parser'); 4 5 app.use(express.static('page')); 6 app.use(bodyParser.raw()); 7 8 app.post("/csJSON",csJSONFun); 9 10 app.listen(12306); 11 12 function csJSONFun(request,response){ 13 request.on("data",function(data){ 14 console.log(data); 15 response.writeHead(200); 16 response.write(data.toString()); 17 response.end(); 18 }); 19 }
客户端测试代码:
1 rawAjaxFunc(function (data) { 2 console.log(data); 3 }); 4 function rawAjaxFunc(callback){ 5 let xhr = new XMLHttpRequest(); 6 xhr.open('POST', 'csJSON', true); 7 // xhr.open('GET', 'csJSON?app=express&text=cs', true); 8 xhr.setRequestHeader('Content-type','application/json'); 9 xhr.send(JSON.stringify({app:'express',text:'cs'})); 10 xhr.onreadystatechange = function(){ 11 // 监听到readystate=4时 12 // 解析服务器返回的responseText数据 13 if(xhr["readyState"] === 4){ 14 //判断响应状态是否为200--表示请求成功响应 15 if(xhr["status"] === 200){ 16 callback(xhr["responseText"]); 17 } 18 } 19 } 20 }
测试结果:
//服务--14行打印: <Buffer 7b 22 61 70 70 22 3a 22 65 78 70 72 65 73 73 22 2c 22 74 65 78 74 22 3a 22 63 73 22 7d> //客户端答应 {"app":"express","text":"cs"}
除了使用express.raw()中间件将请求有效内容转换成Buffer类型,还可以在其他基于body-parser中间件中通过可选参数options的verify来转换请求的有效内容为Buffer类型,例如express.json中的实现:
1 app.use(bodyParser.json({ 2 verify: function (req, res, buf, encoding) { 3 req.rawBody = buf; 4 } 5 })); 6 7 //接口示例 8 function csJSONFun(request,response){ 9 console.log(request.rawBody); 10 ... 11 }
2.5express.text([options]):这是Express中的内置中间件功能。它将传入的请求有效负载解析为字符串,并且基于 body-parser。实际上由于数据转换的安全性,依然时将数据转换成了Buffer类型,基本与express.raw()无异(字符编码一致的情况下),但是要注意字符集。
Property(属性) | Description(描述) | Type(类型) | Default(默认值) |
defaultCharset | 如果未在Content-Type 请求的标题中指定字符集,则为文本内容指定默认字符集。 |
String | "utf-8" |
type | 这用于确定中间件将解析的媒体类型。此选项可以是字符串,字符串数组或函数。如果不是函数,则将type 选项直接传递到type-is库,该名称可以是扩展名(如txt ),MIME类型(如text/plain )或带有通配符的MIME类型(如*/* 或text/* )。如果是函数,则将type 选项称为as fn(req) ,如果请求返回真实值,则将解析请求。 |
混合(一般使用字符串) | "text/plain" |
express.text()的options还包含与express.raw()options一致的属性:inflate、limit、verify。
//测试将上面的app.use(bodyParser.raw())修改成text就可以了 app.use(bodyParser.text());
2.6express.router([options])后面会有一篇关于Express路由的解析博客,这里就不重复了。
注:express上的API主要用于定义Express框架对http连接对象的解析模型,比如前面的json定义了express解析post请求的JSON格式数据、static定义了express响应静态资源的的一系列行为模式、row定义了将请求数据转换成Buffer类型、text定义了将请求数据转换成字符串类型、urlencoded定义了如何解析请求路径,如(编码格式、控制url大小等)
三、express功能分析
3.1Application:在官方文档中将其描述为Express应用程序。
通过express()即Express模块导出的顶级函数来创建,这一点已经不需要过多的解释,既然Application是Express的应用程序,所以它也承载了Express的主要功能实现,例如app.use()负责添加Express的中间件,app.get()、app.post()、app.delete()负责注册各种请求响应回调函数。这些都是在实际应用中经常被使用也是主要使用的API。
当然也还包括负责启动http服务的app.listen()等Express封装HTTP模块的功能,所以Express也还包含了Request和Response两个子模块,这与nodejs的原生HTTP模块非常类是,Application更加集成而方便简单的管理各种请求和响应操作。
3.2Router:在官方文档中将其描述为Express的中间件和路由分离的实例。
在官方的描述中包含几个关键字:中间件、路由、实例。
中间件:在计算机系统应用中的定义是介于系统和应用软件之间的一类软件,比如在个人电脑中我们有时后会通过物理接口接入一些设备(如:声卡或者显卡),系统中可能没有直接取动这些设备的功能,这时候设备产商会提供一些驱动程序,这类驱动程序就是设备本身的软件和系统的中间件。在Express的中间件可以理解为nodejs环境自带的HTTP模块在响应网络请求之前的的一系列自定义程序。
路由:路由一词本来是用来描述分配网络资源的一种设备,由于其功能就是用来处理端到端的网络连接资源分配。我们在开发nodejs后台时为了更规范的管理资源,也将请求根据请求url进行规划整理成类似端到端的分配方式(比如:首页的js文件资源路径为.../js/homePage/xxx.js;首页的图片文件资源路径为.../image/homePage/xxx.jpg等),这种资源路径的逻辑分配就会体现到具体的HTTP请求接口管理中。而在Express中它更友好的封装了各种请求方法的管理模式,在基于Express开发时只需要调用不同的请求方法的API将我们响应对应资源的回调函数作为参数传入即可,当然还可以设置具体的路径(例如:get('/page/xxxx.xx',function(req,res){...})),也是通常我们所说的路由。
实例:在面向对象中最重要的概念就是类和实例,关于这方面就不做太多解释了。在这里不能单独看“实例”这两个字,而是要看“中间件和路由分离的实例”,这句话的意思就是Express中具体实现中间件和路由分离的是Router模块,至于怎么具体分离在后面一篇博客中会通过解析源码的方式分析。这里重点关注一下Router与Application的关系,因为实际上是通过Application.use()添加中间件,通过Application.get()等方法注册路由,而不是通过Router.use()添加中间件,并也不是通过Router.get()注册路由。实际上Application.use调用的就是Router.use,路由同理,Application是为Express的具体功能实现抛出接口。
虽然后面会有源码解析对Express的中间件和路由进行详细的解析,这里还是简单的解释以下这两者的关系,Express通过Router来管理中间件和路由,实际上就是当请求被服务接收到以后,Express会先指向对应请求的中间件程序,然后再调用路由对应的响应回调,再结合前面关于路由的解析应该就很清晰了。
3.3Request与Response
这两个模块就是直接对应了nodejs中原生HTTP的请求对象模型Request和会话对象模型Response,并进行了一些友好的封装,这些东西就不一一解释了,详细可以参考官方文档:
https://www.expressjs.com.cn/4x/api.html#req
https://www.expressjs.com.cn/4x/api.html#res
(提示:我测试的4.x版已经內置body-parser中间件,不再需要另外安装,所以可以直接使用express.json(),例如: app.use(express.json()); )