更好阅读请戳 这里

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. 1.16. BIP39协议:使用助记词生成确定性钱包

    以太坊系统学习教程: https://www.netkiller.cn/blockchain/bip39.html 1.16. BIP39协议:使用助记词生成确定性钱包 BIP:39 层:应用层 标题 ...

  2. 树莓派初次使用的基本配置.md

    记录了一下树莓派初次使用的配置过程,包括装系统.修改 IP 等等. 树莓派(英语:Raspberry Pi),是一款基于 Linux 的单板机电脑. 它由英国的树莓派基金会所开发,目的是以低价硬件及自 ...

  3. Linux nohup 后台运行命令

    有一些爬虫的程序需要在后台运行,所以简单总结了一下nohup 的一些用法 基本命令:nohup command  $; 运行之后出现nohup: ignoring input and appendin ...

  4. 一个简单的NetCore项目:1 - 搭建框架,生成数据库

    1- 启动项目 安装.NETCORE SDK,教程在网上可以搜索的到,这里就不讲述了.简单粗暴的方式就是安装最新的VS2015. 2-搭建框架 2.1 打开VS新建一个项目,在弹出的新建项目对话框中, ...

  5. java long值转成时间格式

    /** * 将long值转换为以小时计算的格式 * @param mss * @return */ public static String formatLongTime(long mss) { St ...

  6. 深夜浅谈我理解的DIV对SEO的影响

    又到了夜深人静的时候,对于以前的我来说每天的这个时候都是在敲一下代码啊或者看一会书,但是今夜突然间又一次心血来潮,想写一篇博文来记录一下这一段时间做SEO优化所遇到的问题. 其实对于我来说SEO并不是 ...

  7. 【loj6177】「美团 CodeM 初赛 Round B」送外卖2 Floyd+状压dp

    题目描述 一张$n$个点$m$条边的有向图,通过每条边需要消耗时间,初始为$0$时刻,可以在某个点停留.有$q$个任务,每个任务要求在$l_i$或以后时刻到$s_i$接受任务,并在$r_i$或以前时刻 ...

  8. Visual Source Safe的使用方法

    VSS 的全称为 Visual Source Safe .作为 Microsoft Visual Studio 的一名成员,它主要任务就是负责项目文件的管理,几乎可以适用任何软件项目.管理软件开发中各 ...

  9. [洛谷P2197]nim游戏

    题目大意:Nim游戏.地上有n堆石子,每人每次可从任意一堆石子里取出任意多石子,不能不取,且每次只能从一堆里取.没石子可取的人输.问是否存在先手必胜的策略. 题解:Nim游戏有一个定理,就是当所有棋子 ...

  10. [bzoj] 1257 余数之和sum || 数论

    原题 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + - + k mod n的值,其中k mod i表示k除以i的余数. \(\sum^n_{i=1} ...