博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
express运行原理
阅读量:6938 次
发布时间:2019-06-27

本文共 3825 字,大约阅读时间需要 12 分钟。

一、express底层: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中间件

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

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

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

function uselessMiddleware(req, res, next) {  next();}

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

function uselessMiddleware(req, res, next) {  next('出错了!');}

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

  在 Node.js Web 开发中,各种模块基本采用这样的中间件格式:

function (req, res, next) {  // req 用于获取请求信息, ServerRequest 的实例  // res 用于响应处理结果, ServerResponse 的实例  // next() 函数用于将当前控制权转交给下一步处理,如果给 next() 传递一个参数时,表示出错信息}

  Express 是基于 Connect 的, Connect 中间件采用了以上的这种格式。 因此,当你要编写一个中间件时,编写一个以上格式的函数即可。

  其实跟编写 Express 的路由处理函数是没多大区别的,一些细微的差别是:

  • 中间件一般不直接对客户端进行响应,而是对请求进行一些预处理,再传递下去;
  • 中间件一般会在路由处理之前执行;

  比如:

// 检查用户是否登录中间件,所有需要登录权限的页面都使用此中间件function checkLogin (req, res, next) {  if (req.session.user) {    next();  } else {    res.redirect('/');  }}

三、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('/', someMiddleware); 

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

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

  

var express = require("express");var http = require("http");var app = express();app.use("/", 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);

 

  参考资料:

  

  

 

转载地址:http://ljfnl.baihongyu.com/

你可能感兴趣的文章
微信公众平台的静默授权和网页授权区别详解
查看>>
JAVA和C#检测IP地址段是否交叉和获取地址段IP列表的方法
查看>>
深入浅出的webpack4构建工具---比mock模拟数据更简单的方式(二十一)
查看>>
Spring Boot 整合 Thymeleaf 完整 Web 案例
查看>>
DAX的圈圈大坑:循环依赖关系错误circular dependency (单表篇)
查看>>
gitlab 备份
查看>>
系统进不去怎么办?教你利用bootice工具引导修复系统
查看>>
CentOS 7下启动postfix服务报错:fatal: parameter inet_interfaces: no local interface found for ::1...
查看>>
python测试开发django-6.模板中include使用
查看>>
博客园以后不再更新
查看>>
『流畅的Python』第13章:正确重载运算符
查看>>
Android 系统(64)---Android中m、mm、mmm、mma、mmma的区别【转】
查看>>
常用内存数据库介绍
查看>>
JSP基本面试的试题
查看>>
Handling Checkboxes, Radio Buttons and Select Options in jQuery [转]
查看>>
DD-WRT--让我们的无线路由器用上Linux
查看>>
《软件工程》大作业的想法和完成的过程
查看>>
一维最大子数组
查看>>
UTF-8编码的空格(194 160)问题
查看>>
PyQt4学习资料汇总 (转)
查看>>