肢解 HTTP 服务器构建
更好阅读请戳 这里
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模块
函数封装
将我们的脚本封装到一个函数里面,然后导出该封装函数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;
模块引用
// 如主文件名为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 服务器构建的更多相关文章
- 优化系统资源ulimit《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》
优化系统资源ulimit<高性能Linux服务器构建实战:运维监控.性能调优与集群应用> 假设有这样一种情况,一台Linux 主机上同时登录了10个用户,在没有限制系统资源的情况下,这10 ...
- 优化Linux内核参数/etc/sysctl.conf sysctl 《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》
优化Linux内核参数/etc/sysctl.conf sysctl <高性能Linux服务器构建实战:运维监控.性能调优与集群应用> http://book.51cto.com/ar ...
- 常用服务器构建 ftp
ftp服务器1.安装vsftpd服务器sudo apt-get install vsftpd2.配置vsftpd.conf文件sudo vi /etc/vsftpd.conf添加下面设置anonymo ...
- 常见的linux服务器构建
Linux常用服务器构建-ftp服务器 ftp服务器 FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”. 用于Internet上的控制文件的双 ...
- AliRedis单机180w QPS, 8台服务器构建1000w QPS Cache集群(转)
http://blog.sina.com.cn/s/blog_e59371cc0101br74.html 引言: 如今redis凭借其高性能的优势, 以及丰富的数据结构作为cache已越 ...
- 来玩一局CS吗?UE4射击游戏的独立服务器构建
前言 根据UE4官方文档的介绍,UE4引擎在架构时就已经考虑到了多人游戏的情景,多人游戏基于客户端-服务器模式(CS模式).也就是说,会有一个服务器担当游戏状态的主控者,而连接的客户端将保持近似的 ...
- Linux教学资源服务器构建
1. 需求分析 1.1 课题简介 随着计算机互联网的迅速发展,大多数学校已经实现教学的信息化,从传统的黑板教学方式转变为现阶段的多媒体教学,教学的资源,素材课件,甚至学生的作业也都实现数字化,为了实现 ...
- vsts + XX云服务器构建netcore+docker持续集成交付部署
持续集成交付部署是什么意思,它给我们带来什么好处? 先贴一张图 持续集成(Continuous Integration) 持续集成强调开发人员提交了新代码之后,立刻进行构建.(单元)测试(这个要看情况 ...
- 高性能Linux服务器构建实战笔记
一. web应用篇 1 HTTP服务器Nginx 1.1 性能上.功能上.安装上与Apache对比 l 性能上占用系统资源少,支持并发高 ...
随机推荐
- Git的使用和部署
Git是什么? Git是目前世界上最先进的分布式版本控制系统(没有之一). 什么是版本控制系统? 没有版本控制系统 有了版本控制系统 版本 文件名 用户 说明 日期 1 service.doc 张三 ...
- Python之tornado框架原理
Python web框架 1.简单概念 tornado socket.逻辑处理 Django flask 逻辑处理 第三方处理模块(包含了socket) jinja2模块 Models 数据库处理 V ...
- BZOJ 3925 ZJOI2015 地震后的幻想乡 状压dp+期望
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3925 题意概述: 给出一张N点M边的最小生成树,其中每条边的长度为[0,1]的实数,求最小 ...
- C++STL中的vector的简单实用
[原创] 使用C++STL中的vector, #include <stdio.h> #include<stdlib.h> #include<vector> usin ...
- ArcGIS Engine开发中利用GP工具时常出现的错误
在用GP工具的时候常常会碰到这个错误: 调用 GP 对 COM 组件的调用返回了错误 HRESULT E_FAIL 解决方案: 这种情况一般有两种可能. 1.AE程序的license的级别不够. 2. ...
- [转] UnityVS(Visual Studio Tools For Unity)的安装与使用
一些废话 Unity 的开发者们,尤其是微软系的Unity开发者们,用Mono是不是烦死了?你是不是跟我一样,用vs来写代码,用Mono来跟踪调试?好麻烦啊好麻烦. 也许你会说,傻逼你不会用Unity ...
- [剑指Offer] 42.和为S的两个数字
题目描述 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 输出描述: 对应每个测试案例,输出两个数,小的先输出. [思 ...
- 【loj6191】「美团 CodeM 复赛」配对游戏 概率期望dp
题目描述 n次向一个栈中加入0或1中随机1个,如果一次加入0时栈顶元素为1,则将这两个元素弹栈.问最终栈中元素个数的期望是多少. 输入 一行一个正整数 n . 输出 一行一个实数,表示期望剩下的人数, ...
- 【bzoj2049】[Sdoi2008]Cave 洞穴勘测 LCT
题目描述 辉辉热衷于洞穴勘测.某天,他按照地图来到了一片被标记为JSZX的洞穴群地区.经过初步勘测,辉辉发现这片区域由n个洞穴(分别编号为1到n)以及若干通道组成,并且每条通道连接了恰好两个洞穴.假如 ...
- P1140 相似基因
题目背景 大家都知道,基因可以看作一个碱基对序列.它包含了4种核苷酸,简记作A,C,G,T.生物学家正致力于寻找人类基因的功能,以利用于诊断疾病和发明药物. 在一个人类基因工作组的任务中,生物学家研究 ...