更好阅读请戳 这里

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. errno -4058 and npm WARN enoent ENOENT 解决方案

    1.报错如下: npm WARN checkPermissions Missing write access to C:\Users\hejinrong\AppData\Roaming\npm\nod ...

  2. c++知识点总结--函数模板

    通用函数可变参模板 用于处理不限定参数的函数 showall(){//空函数,接口,最后结束递归 } template<typename T,typename... Args> void ...

  3. HTTP 知新

    REST 先从 REST 的角度来看看 HTTP 协议规范, URL:需要操作的对象,也就是资源 HTTP method:我要对该对象做什么(POST 增.DELETE 删.GET 查.PUT 和 P ...

  4. input设置为readonly后js设置intput的值后台仍然可以接收到

    今天发现一个奇怪现象,一个input属性readonly的值被设置为readonly,然后有前台js给input设置了新值. 虽然前台看不到效果,但是提交到后台后,仍然可以接收到新值,感觉很奇怪. 我 ...

  5. PAT java大数 A+B和C

    题目描述: 给定区间[-, ]内的3个整数A.B和C,请判断A+B是否大于C. 输入格式: 输入第1行给出正整数T(<=),是测试用例的个数.随后给出T组测试用例,每组占一行,顺序给出A.B和C ...

  6. .Net MVC中使用css 和js

    @section script { <script language="javascript"> </script> }

  7. 【Linux】——搭建redis

    1.准备安装文件 redis-3.0.5.tar.gz redis-desktop-manager(可视化管理工具) 2.解压.编译 软件存放目录:/usr/local/software 解压存放路径 ...

  8. 【bzoj1787】[Ahoi2008]Meet 紧急集合 倍增LCA

    题目描述 输入 输出 样例输入 6 4 1 2 2 3 2 4 4 5 5 6 4 5 6 6 3 1 2 4 4 6 6 6 样例输出 5 2 2 5 4 1 6 0 题解 倍增LCA 首先有集合点 ...

  9. ASP.NET页面之间传值Server.Transfer(4)

    这个才可以说是面象对象开发所使用的方法,其使用Server.Transfer方法把流程从当前页面引导到另一个页面中,新的页面使用前一个页面的应答流,所以这个方法是完全面象对象的,简洁有效. Serve ...

  10. Java23个设计模式的简明教程

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...