更好阅读请戳 这里

1. 最简单的 http 服务器

// server.js

var http = require("http");

http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888); // node server.js
// 打开http://localhost:8888/,你会看到一个写着“Hello World”的网页~

首先我们来看看服务端模式下如何工作:

  • 首先需要使用.createServer方法创建一个服务器
  • 然后调用.listen方法监听端口
  • 之后,每当来了一个客户端请求,创建服务器时传入的回调函数就被调用一次。可以看出,这是一种事件机制

HTTP请求本质上是一个数据流,由请求头(headers)和请求体(body)组成

// 请求头
POST / HTTP/1.1
User-Agent: curl/7.26.0
Host: localhost
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded // 请求体
Hello World

HTTP请求在发送给服务器时,可以认为是按照从头到尾的顺序一个字节一个字节地以数据流方式发送的。而http模块创建的HTTP服务器在接收到完整的请求头后,就会调用回调函数。在回调函数中,可以使用request对象访问请求头数据并把request对象当作一个只读数据流来访问请求体数据

可修改上述代码

// server.js

var http = require("http");

http.createServer(function(request, response) {
// 读取 requst 数据流
console.log('我是请求方法:', request.method)
console.log('我是请求头:', request.headers) request.on('data', function (chunk) {
body.push(chunk);
});
request.on('end', function () {
body = Buffer.concat(body);
console.log('我是请求体呀', body.toString());
}); // 处理response
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888); // node server.js
// 打开http://localhost:8888/,你会看到一个写着“Hello World”的网页~

就这么简单,本文 完~

oh,no

you too young, too simple

2. 肢解代码

  • var http = require("http")

    • 请求(require)Node.js自带的 http 模块,并且把它赋值给 http 变量
  • createServer

    • listen 方法-数值参数指定该 HTTP 服务器监听的端口号
  • createServer 的参数

    • 基于事件驱动的回调

      • 无论何时我们的服务器收到一个请求,这个函数就会被调用
  • 请求处理

    onRequest() 函数被触发的时候,有两个参数对象

    • request
    • response
      // 发送一个HTTP状态200和HTTP头的内容类型
      response.writeHead(200, {"Content-Type": "text/plain"});
      // 添加HTTP主体内容
      response.write("Hello World");
      // 完成响应
      response.end();

3. 模块封装

这一步我们把server.js变成一个真正的Node.js模块

  1. 函数封装

    将我们的脚本封装到一个函数里面,然后导出该封装函数

    var http = require("http");
    
    function start() {
    function onRequest(request, response) {
    console.log("Request received.");
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
    } http.createServer(onRequest).listen(8888);
    console.log("Server has started.");
    } exports.start = start;
  2. 模块引用

    // 如主文件名为index.js,写入
    var server = require("./server"); server.start();

    执行 node index.js

4. 路由

所有请求数据都在 request对象中,数据解析,还需要 url, querystring模块

来,我们试一试找出浏览器的请求路径~

4.1 获取路由

var http = require("http");
var url = require('url') function start(){
function onRequest(req, res){
var url = url.parse(req.url)
// 打印 url 信息
console.log('server start url', url)
res.writeHead(200, {"content-type": "text/plain"})
res.end()
}
http.createServer(onRequest).listen(8888)
} exports.start = start

request.url参数打印:

4.2 有路可寻

引入路由处理

  • 创建route.js,处理路由信息,在index页面引入该模块,并作为 server 中start 函数的参数执行,
  • 解析每一个request,获取其url 路径进行处理
// server.js
var http = require("http");
var url = require('url') function start(route){
function onRequest(req, res){
var pathname = url.parse(req.url).pathname
route(pathname)
res.writeHead(200, {"content-type": "text/plain"})
res.end()
}
http.createServer(onRequest).listen(8888)
} exports.start = start

// route.js
function route(pathname){
console.log('route', pathname)
} exports.route = route // index.js 引入route
var server = require('./server')
var router = require('./route')
server.start(router.route)

以上代码我们实现了有路可寻

为了避免多重的 if..else..,我们通过对象传递一系列请求

  • 首先创建一个 requestManager 模块,导出多个处理函数

  • 创建 managers 对象:映射不同路由的处理方法

  • 将路由与函数的映射关系作为参数传递给 server

  • server 中调用 route 的处理结果

    // requestManager.js
    function start(){
    console.log('route-----start')
    return 'hello start'
    }
    function next(){
    console.log('route-----next')
    return 'hello next'
    }
    exports.start = start
    exports.next = next
    // index.js
    var server = require('./readfile')
    var router = require('./route')
    var requestManager = require('./requestManager') var managers = []
    managers['/'] = requestManager.start
    managers['/start'] = requestManager.start
    managers['/next'] = requestManager.next server.start(router.route, managers) // http://localhost:8888/start, 浏览器会输出“hello start”
    // http://localhost:8888/next 会输出“hello next”
    // http://localhost:8888/chaoran 会输出“404”。
  • manager :每一个路由提供对应的处理函数

    // server.js
    var http = require("http");
    var url = require('url') function start(route, manager){
    function onRequest(req, res){
    var pathname = url.parse(req.url).pathname
    console.log('server request for', pathname)
    var content = route(pathname, manager)
    res.writeHead(200, {"content-type": "text/plain"})
    res.write(content)
    res.end()
    }
    http.createServer(onRequest).listen(8888)
    } exports.start = start
  • 取出managers 中的路由事件进行处理

    // route.js
    function route(pathname, managers){
    console.log('rrr', pathname)
    if(typeof managers[pathname] == 'function'){
    return managers[pathname]() }else {
    console.log('managers no found')
    return ''
    }
    } exports.route = route

好啦,用是能用的,就是偶尔会挂 ( ﹁ ﹁ ) ~→

至于node中的并行及如何实现非阻塞,下次我们结合实例来学习~

参考:

肢解 HTTP 服务器构建的更多相关文章

  1. 优化系统资源ulimit《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化系统资源ulimit<高性能Linux服务器构建实战:运维监控.性能调优与集群应用> 假设有这样一种情况,一台Linux 主机上同时登录了10个用户,在没有限制系统资源的情况下,这10 ...

  2. 优化Linux内核参数/etc/sysctl.conf sysctl 《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》

    优化Linux内核参数/etc/sysctl.conf  sysctl  <高性能Linux服务器构建实战:运维监控.性能调优与集群应用> http://book.51cto.com/ar ...

  3. 常用服务器构建 ftp

    ftp服务器1.安装vsftpd服务器sudo apt-get install vsftpd2.配置vsftpd.conf文件sudo vi /etc/vsftpd.conf添加下面设置anonymo ...

  4. 常见的linux服务器构建

    Linux常用服务器构建-ftp服务器 ftp服务器 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”. 用于Internet上的控制文件的双 ...

  5. AliRedis单机180w QPS, 8台服务器构建1000w QPS Cache集群(转)

    http://blog.sina.com.cn/s/blog_e59371cc0101br74.html 引言:        如今redis凭借其高性能的优势, 以及丰富的数据结构作为cache已越 ...

  6. 来玩一局CS吗?UE4射击游戏的独立服务器构建

    前言   根据UE4官方文档的介绍,UE4引擎在架构时就已经考虑到了多人游戏的情景,多人游戏基于客户端-服务器模式(CS模式).也就是说,会有一个服务器担当游戏状态的主控者,而连接的客户端将保持近似的 ...

  7. Linux教学资源服务器构建

    1. 需求分析 1.1 课题简介 随着计算机互联网的迅速发展,大多数学校已经实现教学的信息化,从传统的黑板教学方式转变为现阶段的多媒体教学,教学的资源,素材课件,甚至学生的作业也都实现数字化,为了实现 ...

  8. vsts + XX云服务器构建netcore+docker持续集成交付部署

    持续集成交付部署是什么意思,它给我们带来什么好处? 先贴一张图 持续集成(Continuous Integration) 持续集成强调开发人员提交了新代码之后,立刻进行构建.(单元)测试(这个要看情况 ...

  9. 高性能Linux服务器构建实战笔记

    一.            web应用篇 1           HTTP服务器Nginx 1.1          性能上.功能上.安装上与Apache对比 l  性能上占用系统资源少,支持并发高 ...

随机推荐

  1. mysql分布式技术

    所有的分布式技术 dobble zokkiper ngix

  2. 【SSH】——封装参数不确定的分页查询

    [前言] 在BS中,分页技术的应用相当频繁.说到分页,简单的分页就很好实现了,如果在分页的基础上再加上业务逻辑,这就使得分页的技术更加的灵活了. [简单分页] 我们先看一种简单的分页,为了做到复用,我 ...

  3. 【历史】- .NET之父 - Anders Hejlsberg

    简介 安德斯·海尔斯伯格(Anders Hejlsberg,1960.12~),丹麦人,Turbo Pascal编译器的主要作者,Delphi和.NET之父! 安德斯·海尔斯伯格曾在丹麦技术大学学习工 ...

  4. 深入研究java.lang.Runtime类(转)

    一.概述      Runtime类封装了运行时的环境.每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接.      一般不能实例化一个Runtime对象, ...

  5. 【BZOJ3674】可持久化并查集加强版

    可持久化并查集我觉得就是可持久化数组的一种应用.可持久化数组,顾名思义,就是有历史版本的数组,那么如果我们暴力修改储存的话,修改O(n)查询O(1),空间O(n*m),这样肯定不可行,那么我们发现主席 ...

  6. 7月24号day16总结

    一开始显示出现问题,js路径不能应用,因为用的是springMVC框架书写,所以有路径的保护和静态引用地址时需要注意的地方 今天进行了最后项目的优化,包括map清洗数据部分的代码和echarts显示的 ...

  7. MySQL rpm 版本安装

     准备: [root@localhost moudles]# ls MySQL-client-5.6.36-1.linux_glibc2.5.x86_64.rpm MySQL-server-5.6.3 ...

  8. 自建git服务器搭建使用记录

    git在push的时候出现insufficient permission for adding an object错误 //解决方法,在git库的目录下 //明明一开始创建user的时候有执行这个命令 ...

  9. es6+最佳入门实践(7)

    7.set和map数据结构 7.1.什么是set? Set就是集合,集合是由一组无序且唯一的项组成,在es6中新增了set这种数据结构,有点类似于数组,但是它的元素是唯一的,没有重复 let st = ...

  10. java中的构造块、静态块等说明

    一:这篇博客写的时候我在学校已经一个星期了,为什么又会想到写这le,因为这几天又在重新学下有关spring.myBatis的知识,其中在实例化sessionFactory的时候用到了静态块,虽然在学习 ...