Node.js开发的目的就是为了用JavaScript编写Web服务器程序。因为JavaScript实际上已经统治了浏览器端的脚本,其优势就是有世界上数量最多的前端开发人员。如果已经掌握了JavaScript前端开发,再学习一下如何将JavaScript应用在后端开发,就是名副其实的全栈了。

HTTP协议

要理解Web服务器程序的工作原理,首先,我们要对HTTP协议有基本的了解。如果你对HTTP协议不太熟悉,先看一看HTTP协议简介。

HTTP服务器

要开发HTTP服务器程序,从头处理TCP连接,解析HTTP是不现实的。这些工作实际上已经由Node.js自带的http模块完成了。应用程序并不直接和HTTP协议打交道,而是操作http模块提供的requestresponse对象。

request对象封装了HTTP请求,我们调用request对象的属性和方法就可以拿到所有HTTP请求的信息;

response对象封装了HTTP响应,我们操作response对象的方法,就可以把HTTP响应返回给浏览器。

用Node.js实现一个HTTP服务器程序非常简单。我们来实现一个最简单的Web程序hello.js,它对于所有请求,都返回Hello world!

'use strict';

// 导入http模块:
var http = require('http'); // 创建http server,并传入回调函数:
var server = http.createServer(function (request, response) {
// 回调函数接收request和response对象,
// 获得HTTP请求的method和url:
console.log(request.method + ': ' + request.url);
// 将HTTP响应200写入response, 同时设置Content-Type: text/html:
response.writeHead(200, {'Content-Type': 'text/html'});
// 将HTTP响应的HTML内容写入response:
response.end('<h1>Hello world!</h1>');
}); // 让服务器监听8080端口:
server.listen(8080); console.log('Server is running at http://127.0.0.1:8080/');

在命令提示符下运行该程序,可以看到以下输出:

$ node hello.js
Server is running at http://127.0.0.1:8080/

不要关闭命令提示符,直接打开浏览器输入http://127.0.0.1:8080,即可看到服务器响应的内容:hello world!

同时,在命令提示符窗口,可以看到程序打印的请求信息:

GET: /
GET: /favicon.ico

这就是我们编写的第一个HTTP服务器程序!

文件服务器

让我们继续扩展一下上面的Web程序。我们可以设定一个目录,然后让Web程序变成一个文件服务器。要实现这一点,我们只需要解析request.url中的路径,然后在本地找到对应的文件,把文件内容发送出去就可以了。

解析URL需要用到Node.js提供的url模块,它使用起来非常简单,通过parse()将一个字符串解析为一个Url对象:

'use strict';

var url = require('url');

console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash'));

结果如下:

Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'host.com:8080',
port: '8080',
hostname: 'host.com',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/path/to/file',
path: '/path/to/file?query=string',
href: 'http://user:pass@host.com:8080/path/to/file?query=string#hash'
}

处理本地文件目录需要使用Node.js提供的path模块,它可以方便地构造目录:

'use strict';

var path = require('path');

// 解析当前目录:
var workDir = path.resolve('.'); // '/Users/michael' // 组合完整的文件路径:当前目录+'pub'+'index.html':
var filePath = path.join(workDir, 'pub', 'index.html');
// '/Users/michael/pub/index.html'

使用path模块可以正确处理操作系统相关的文件路径。在Windows系统下,返回的路径类似于C:\Users\michael\static\index.html,这样,我们就不关心怎么拼接路径了。

最后,我们实现一个文件服务器file_server.js

'use strict';

var
fs = require('fs'),
url = require('url'),
path = require('path'),
http = require('http'); // 从命令行参数获取root目录,默认是当前目录:
var root = path.resolve(process.argv[2] || './static'); console.log('Static root dir: ' + root); // 创建服务器:
var server = http.createServer(function (request, response) {
// 获得URL的path,类似 '/css/bootstrap.css':
var pathname = url.parse(request.url).pathname;
// 获得对应的本地文件路径,类似 '/srv/www/css/bootstrap.css':
var filepath = path.join(root, pathname);
// 获取文件状态:
fs.stat(filepath, function (err, stats) {
if (!err && stats.isFile()) {
// 没有出错并且文件存在:
console.log('200 ' + request.url);
// 发送200响应:
response.writeHead(200);
// 将文件流导向response:
fs.createReadStream(filepath).pipe(response);
} else {
// 出错了或者文件不存在:
console.log('404 ' + request.url);
// 发送404响应:
response.writeHead(404);
response.end('404 Not Found');
}
});
}); server.listen(8080); console.log('Server is running at http://127.0.0.1:8080/');

没有必要手动读取文件内容。由于response对象本身是一个Writable Stream,直接用pipe()方法就实现了自动读取文件内容并输出到HTTP响应。

在命令行运行node file_server.js /path/to/dir,把/path/to/dir改成你本地的一个有效的目录(要设置就设置绝对路径,要不就不设置),然后在浏览器中输入http://localhost:8080/index.html

就出现了html内容!!

将上面的代码进化以下,当url没有输入/index.html时,或则只输了个域名,默认显示index.html页面

'use strict'
//搭建一个文件服务器
var fs=require("fs"),
url=require("url"),
path=require("path"),
http=require("http"); // 从命令行参数获取root目录,默认是当前目录:
var root=path.resolve(process.argv[2] || './static');//设置static目录为静态资源的跟目录
console.log(process.argv);
console.log('Static root dir: ' + root);
// 用此目录 node file_server.js /static 运行项目时
// root: C:\static 这样运行肯定是不行的 要不不加路径 要不加static文件夹的绝对路径 // 创建服务器:
var server=http.createServer(function(request,response){
// 获得URL的path,类似 '/css/bootstrap.css':
var pathname = url.parse(request.url).pathname;//url用来解析请求地址
console.log(pathname);// /index.html
// 获得对应的本地文件路径,类似 '/srv/www/css/bootstrap.css':
var filepath = path.join(root, pathname);
console.log(filepath);//C:\static\index.html
// 获取文件状态:
fs.stat(filepath,function(err,stats){
if(!err&&stats.isFile()){
// 没有出错并且文件存在:
console.log('200 ' + request.url);
// 发送200响应:
response.writeHead(200);
// 将文件流导向response:
fs.createReadStream(filepath).pipe(response);
}else if(!err&&stats.isDirectory()){//若是目录 向下搜索index.html
response.writeHead(404);//报个404错误
var testFilePath=path.join(filepath,'index.html');
fs.stat(testFilePath,function(err,stats){
if(!err&&stats.isFile()){
fs.createReadStream(testFilePath).pipe(response);
}
})
}else{
// 出错了或者文件不存在:
console.log('404 ' + request.url);
// 发送404响应:
response.writeHead(404);
response.end('404 Not Found');
}
})
}); //服务器监听8080端口
server.listen(8080); console.log('Server is running at http://127.0.0.1:8080/');

node中的http内置模块的更多相关文章

  1. node中的crypto内置模块

    crypto模块的目的是为了提供通用的加密和哈希算法.用纯JavaScript代码实现这些功能不是不可能,但速度会非常慢.Nodejs用C/C++实现这些算法后,通过cypto这个模块暴露为JavaS ...

  2. Node中的net模块提供的前端通信

    Node中的net模块提供的前端通信 客户端 业务: 客户端现在要在终端输入内容,然后回车发送内容给服务器 解决: Node中提供了一个叫做 readline 的 模块用于读取命令行内容 [ 单行读取 ...

  3. node中的Stream-Readable和Writeable解读

    在node中,只要涉及到文件IO的场景一般都会涉及到一个类-Stream.Stream是对IO设备的抽象表示,其在JAVA中也有涉及,主要体现在四个类-InputStream.Reader.Outpu ...

  4. 深入理解jQuery、Angular、node中的Promise

    最初遇到Promise是在jQuery中,在jQuery1.5版本中引入了Deferred Object,这个异步队列模块用于实现异步任务和回调函数的解耦.为ajax模块.队列模块.ready事件提供 ...

  5. Node中的定时器详解

    在大多数的业务中,我们都会有一些需求,例如几秒钟实现网页的跳转,几分钟对于后台数据进行清理,node与javascript都具有将代码延迟一段时间的能力.在node中可以使用三种方式实现定时功能:超时 ...

  6. node中的可读流和可写流

    javascript的一个不足之处是不能处理二进制数据,于是node中引入了Buffer类型.这个类型以一个字节(即8位)为单位,给数据分配存储空间.它的使用类似于Array,但是与Array又有不同 ...

  7. node中的Readable - flowing/non-flowing mode

    大家都知道在node中Readable Stream有两种模式: flowing mode和non-flowing mode. 对于flowing mode的Readable Stream, 我们是没 ...

  8. 清理8组nodes中表的历史数据,平均每个node中的表有1.5亿条记录,需要根据date_created字段清理8000W数据记录,这个字段没有索引。

    清理8组nodes中表的历史数据,平均每个node中的表有1.5亿条记录,需要根据date_created字段清理8000W数据记录,这个字段没有索引. 环境介绍  线上磁盘空间不足,truncate ...

  9. 重回博客 谈一谈Node中的异步和单线程

    重回博客,这个帐号之前注册后就只发了一篇博客.听朋友建议,决定一周两次更新. 第一篇谈论一下最近想的比较多的异步的问题. 传统多线程异步 传统的异步是多线程的,当要同时做两件事的时候,他们是执行在不同 ...

随机推荐

  1. 一文看懂java io系统 (转)

    出处:  一文看懂java io系统   学习java IO系统,重点是学会IO模型,了解了各种IO模型之后就可以更好的理解java IO Java IO 是一套Java用来读写数据(输入和输出)的A ...

  2. vue-slick 插件配置

    autoplay 布尔值 false 自动播放 autoplaySpeed 整数 3000 自动播放间隔 centerMode 布尔值 false 中心模式 centerPadding 字符串 ’50 ...

  3. ReLU、LReLU、PReLU、CReLU、ELU、SELU

    ReLU.LReLU.PReLU.CReLU.ELU.SELU 2018年01月22日 22:25:34 luxiaohai的学习专栏 阅读数 28218更多 分类专栏: 深度学习   版权声明:本文 ...

  4. Asp.net core 学习笔记 ef core Surrogate Key, Natural Key, Alternate Keys

    更新: 2019-12-23 foreignkey 并不一样要配上 alternate key,其实只要是 unique 就可以了. 和 sql server 是一样的, 经常有一种错觉 primar ...

  5. CodeFirst实体类中,为什么都把ICollection<x>定义成virtual?

    主要是用于延迟加载,提高性能用的 只有定义成virtual后才可以延迟加载. 延迟加载,默认情况下,延迟加载被支持,如果你希望禁用它,必须显式声明,最好的位置是在 DbContext 的构造器中. p ...

  6. VS显示方法引用

    菜单栏 工具->选项->文本编辑器->所有语言->CodeLens 勾上即可

  7. luogu题解 P3629 【[APIO2010]巡逻】树的直径变式

    题目链接: https://www.luogu.org/problemnew/show/P3629 分析 最近被众多dalao暴虐,这道题傻逼地调了两天才知道错哪 不过这题比较良心给你一个容易发现性质 ...

  8. # 使用scatter()绘制散点图

    使用scatter()绘制散点图 之前写过一篇,使用magic function快速绘图的教程了:https://www.cnblogs.com/jiading/p/11750001.html.但这种 ...

  9. [转载]sklearn多分类模型

    [转载]sklearn多分类模型 这篇文章很好地说明了利用sklearn解决多分类问题时的implement层面的内容:https://www.jianshu.com/p/b2c95f13a9ae.我 ...

  10. 手工实现HttpBasic校验

      HttpBasic: 是RFC中定义的一种控制HTTP协议访问资源的方式.具体当HTTP请求受限资源时,就需要在请求头中添加以"Authorization"为key的heade ...