HTTP开发之Connect工具集——中间件

继学习node.js的TCP API和HTTP API之后,node.js web开发进入了正轨,但这就好像Java的servlet一样,我们不可能使用最基础得Servlet对象去写网站,我们也不能使用最基本的node http API去写一个完整得网站,我们需要更加强大得工具集,web套件,甚至是web开发框架(诸如Java下的Spring MVC),来提供开发者更人性化得web开发环境。

创建网站的基本任务——为何要有中间件

  1. 独立托管静态文件,诸如:html,css,js,images
  2. 处理错误和不存在的地址
  3. 处理不同类型的请求

如果我们上来就直接用上一章的http模块来做的话,我们需要先实现一个“框架”才能做到一个网站最基本的任务,如果是运用生产环境的话,我们希望有这样的一个“框架”——connect工具集,最好称它为工具集,他离所谓的“框架”依旧有点差距。

Connect是基于http API之上的,也就是基于node http模块写出来的,方便web开发者使用,他提供了一些工具方法能够上一些重复性的工作便于实现,让开发者更加专注于应用的功能业务。

Connect已经是十分基础的node web开发工具集,在实际开发中很少看到,以后回介绍稍微高级点的express(对于实际开发来说依然很基础)

特别注意:《了不起的node.js》一书中的代码和connect版本过时了,如果使用最新版的connect需要参照如下方法使用!

导入Connect等中间件模块

Connect模块并非node.js的原生模块,需要引入外部模块

同时还要导入“serve-static”,“content-disposition”提供静态文件访问支持

最终完整package.json:

{
"name":"node-connect",
"version":"0.0.1",
"description":"Use connect to create a website",
"dependencies":{
"connect":"latest",
"serve-static":"latest",
"content-disposition":"latest"
}
}

node npm包搜索管理网站:https://www.npmjs.com/

注:除了connect外,还导入了serve-static,这个包原本属于connect集合,后官方独立出来了,《了不起的node.js》使用的是1.8.x版本的connect(太老了)还包含着static中间件,这里使用了3.0.0+的版本,则需要额外导入这个静态中间件模块。

这些是官网独立的中间件(Connect/Express负责管理)

将不同功能的中间件从connect独立出来是一件好事,方便管理维护!(对于开发者需要注意查看更新)

npm install

引用connect模块

//引入connect模块
var connect = require("connect");
//依然需要引入http模块
var http = require("http")
//依然使用http模块创建服务器
http.createServer().listen(3000);

connect现在是http中间件,如果使用本文最新的connect版本就不能出现《了不起的node.js》一书中的connect.createServer(),因为connect已经移除了这个方法!!!

createServer交给了http模块去做,充分体现了connect是中间件的特性,而不是代替http!

依然使用http.createServer()创建http服务器!!!

使用serve-static中间件托管静态文件

node本身不像nginx,apache,他不是一个完整的http服务器,而是一个语言解析器。

通过对node.js API的开发,可以构建类似nginx一样的功能,负责提供用户静态页面,这就需要用到serve-static中间件

首先serve-static中间件原本属于connect中间件,现在已经独立出来了,也就说其实和connect关系已经不大了,但我依然将两者放在一回中解说。

静态文件指的是:html,css,图片,js等等

在项目目录下新建一个views目录,存放静态html文件

新建index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>hello world</h1>
</body>
</html>

index.js返回静态页面代码:

//引入http模块
var http = require("http");
//引入serveStatic模块
var serveStatic = require('serve-static')
var finalhandler = require('finalhandler'); var serve = serveStatic(__dirname+'/views',{'index':['index.html','index.htm']}); http.createServer(function(req,res){
serve(req,res,finalhandler(req,res));
}).listen(3000);

finalhandler是什么?

作用是友好处理找不到页面访问不到URL的异常和错误,如果删除,用户访问非法地址将会导致node抛出异常停止工作。

访问首页之外的页面?

views下创建一个hello.html,直接在浏览器地址后面+“/hello.html”即可访问这个页面。

访问图片文件?

如何提示下载文件?

var contentDisposition = require('content-disposition')
var finalhandler = require('finalhandler')
var http = require('http')
var serveStatic = require('serve-static') var serve = serveStatic(__dirname+'/files', {
'index': false,
'setHeaders': setHeaders
}) //强制下载
function setHeaders (res, path) {
res.setHeader('Content-Disposition', contentDisposition(path))
} http.createServer(function onRequest (req, res) {
serve(req, res, finalhandler(req, res))
}).listen(3000);

新建一个files目录,下载的文件放在里面即可。

到此,serve-static中间件简化了开发者托管静态文件的代码,我们不必向上一章那样使用fs+http方式去自己实现输出流文件给浏览器客户端。

使用connect中间件处理不同的请求

在上一回中,如果要对用户不同访问给出对应的返回,我们需要在同一个createServer中不停的写if...else if....else if...else....if.........来判断,这样显得代码十分冗余,而且根本无法把所有情况写清楚,也无法扩展,且根本无法维护。

上一回的部分代码:

	//请求为图片
if(req.method == 'GET' && req.url.substr(-4)==".jpg"){
fs.stat(__dirname+req.url,function(err,stat){
if(err || !stat.isFile()){
res.writeHead(404);
res.end("找不到图片");
return;
}
serve(__dirname+req.url,'application/x-jpg');
});
}else if(req.method=="GET" && req.url=='/'){
//请求为html文件
serve(__dirname+'/form.html','text/html');
}else{
res.writeHead(404);
res.end("网址丢了");
return;
}

接下来使用connect重写这些代码:(代码是基于static-serve那块修改过来的)

//下载文件模块
var contentDisposition = require('content-disposition')
//不需要finalhandler
//var finalhandler = require('finalhandler')
//http模块创建http服务器必须
var http = require('http')
//静态文件托管中间件
var serveStatic = require('serve-static')
//connect工具集
var connect = require("connect");
var app = connect(); app.use(function(req,res,next){
//任何请求都会打印!是必然执行的一步
console.error('%s %s',req.method,req.url)
next();
}); //图片显示
app.use("/images",function(req,res,next){
serveStatic(__dirname+"/images")(req,res,next);
});
//下载文件
app.use("/files",function(req,res,next){
serveStatic(__dirname+"/files",{'index':false,'setHeaders':setHeaders})(req,res,next);
}); //最终处理,所有next都执行不通后到达此处
app.use(function(req,res,next){
res.writeHead(404);
res.end('404 Not Found')
//没有next了,这是最终方法,返回404 not found就行了
}); //强制下载函数
function setHeaders (res, path) {
res.setHeader('Content-Disposition', contentDisposition(path))
}
//建立http服务器
http.createServer(app).listen(3000);

注意到我们依然需要http模块来建立http服务器,然后引入了connect模块,以及之前的serve-static和content-disposition。

这一段代码实际上是把上一回分类请求处理和这一回静态文件托管强强联手了

如果说serve-static这个中间件解决的是静态文件托管的话,那么connect中间件其实是解决了路由,请求定向的控制。这样我们不再需要通过手写的if...else来判断用户请求了什么类型的文件。

next()函数

这个函数在connect中扮演了十分重要的角色,作用:将不同种类的请求线性的串联在一行,每一个app.use()其实类似于原来我们写的if...else语句,next就是在处理不了的情况下,执行另一个app.use(),这样只要回掉函数做不了就抛给下一个做,这样不停的“甩锅”,最终谁都做不了就有一个最终函数,开发者需要建立这样的最终函数,里面没有next()了,说明到最后一步了,必须返回错误给用户看了。我们这里最终函数是一个404错误反馈。

use()函数

第一个参数可以给定一个请求的目录,相对于node执行的项目目录,相当于浏览器网址后面第一个“/”后面的参数。

将js进行到底:node学习5的更多相关文章

  1. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  2. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  3. Node.js环境搭建和学习(windwos环境)

    Node.js环境搭建和学习 一.环境搭建 1.下载安装文件 下载地址http://nodejs-org.qiniudn.com/下载Node.js环境安装包,根据操作系统下载对应的安装包 下载地址 ...

  4. node 学习笔记 - Modules 模块加载系统 (1)

    本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html 用了这么久的 require,但却没有系统的学习过 n ...

  5. [学姿势]实验室搬砖+node学习

    这周开始进行收尾工作,我当然没有进行核心技术的开发,主要负责的是对web端进行展示上的修修补补,主要包括添加VLC播放器.rtsp视频流以及一些js细节. 1.VLC 全称为Video Lan Cli ...

  6. 2015第40周二Node学习

    node历史 今天看cnode开源项目用了io.js,在查这个项目时发现这篇文章node历史,node.js和io.js关系谈到Node.js的由来,不可避免要聊到它的创始人Ryan Dahl.在20 ...

  7. 2015第40周一Node学习

    node学习尝试 早上看了张丹大牛博客文章nodeJS学习路线图和node从零入门系列,感觉获益匪浅,尝试了里面几项内容,对node有了更深入的认识. npm npm是一个node包管理和分发工具,已 ...

  8. Node学习——开篇

    前言:自从下决心转学前端以来,我的专业课java基本荒废了,所以对于后台开发的逻辑也已基本忘干净了.但是作为一名准前端程序猿,我认为还是有必要了解后端开发的,虽不必深入学习,但是能够了解项目从前端到后 ...

  9. node 学习资料

    Node 学习资料: 资料名称 网址 Node.js 中文API文档 http://nodejs.cn/api/ Node 菜鸟教程 http://www.runoob.com/nodejs/node ...

  10. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

随机推荐

  1. ZJNU 2136 - 会长的正方形

    对于n*m网格 取min(n,m)作为最大的正方形边长 则答案可以表示成 s=1~min(n,m) 对于一个s*s的正方形 用oblq数组储存有多少四个角都在这个正方形边上的正方形 以4*4为例 除了 ...

  2. python如何在一个for循环中遍历多个列表

    推荐使用python内置函数zip,它可以将x个y维列表变成一个zip对象,将zip对象拆包可以发现它变成了y个x维元组.我们还可以将这个对象变成一个元组或列表.如下所示: 如果是两个列表的zip,我 ...

  3. Python笔记_第三篇_面向对象_2.第一个Python类

    1. 设计一个类: 设计一个类主要从三个方面进行考虑: 第一:类名:类名要见名知意.首字母大写. 第二:属性. 第三:方法. 备注:在Python中有些东西并不是绝对化的事情,有些根据Python社区 ...

  4. Microsoft.Office.Inter.Excel.dll在調用時可能會出現如下錯誤

    Microsoft.Office.Inter.Excel.dll在調用時可能會出現如下錯誤,具體解決方案如下: 1. 錯誤資訊:檢索 COM 類工廠中 CLSID 為{00024500-0000-00 ...

  5. iOS开发-消息初认识

    一.消息循环(runLoop)的作用 1,防止程序退出, 2,接受事件 3,如果没有事件,让程序自动休眠   二.消息源    1, 输入源:键盘.鼠标.NSBoard.NSPort    2,定时源 ...

  6. tensorflow用法记录

    使用 embedding 变量 import tensorflow as tf import numpy as np sess = tf.InteractiveSession() M = list(' ...

  7. vim中的正则表达式替换

    这个总结的不错 http://tanqisen.github.io/blog/2013/01/13/vim-search-replace-regex/

  8. 关于tomcat报错记录

    启动报错关键信息如下: Caused by: java.lang.IllegalStateException: Unable to complete the scan for annotations ...

  9. java去掉数字后面的0

    有些财务业务场景是需要把数字多余的0去掉的. 可以这么写 private String getRealData(BigDecimal num) { if (num == null) { return ...

  10. vue开发之图片加载不出来问题解决

    在使用vue开发项目的时候,经常会遇到的一个问题就是:图片加载不出来.下面是我总结的几种图片加载不出来的情况及解决办法. 一.项目打包完成后,打开整体空白 1.路径问题 原因 在vue+webpack ...