更好阅读请戳 这里

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. HDU I-最少拦截系统

    http://acm.hdu.edu.cn/showproblem.php?pid=1257 Problem Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦 ...

  2. Hibernate常用方法之_修改

    1.使用session的saveOrUpdate方法 public void updateUser(User user){ Session session = null; Transaction tr ...

  3. 什么是node.js的事件驱动编程

    Node.js现在非常活跃,相关生态社区已经超过Lua(基本上比较知名的功能都有nodejs模块实现).但是我们为何要使用Node.Js?相比传统的webserver服务模式,nodejs有什么优点优 ...

  4. Unescape JavaScript's escape() using C#

    js里面的 unescape escape 对应C#里面 var unescapedString = Microsoft.JScript.GlobalObject.unescape(yourEscap ...

  5. [uva 1350]数位dp+二分

    题目链接:https://vjudge.net/problem/38405 #include<bits/stdc++.h> using namespace std; ][]; ]; lon ...

  6. Codeforces Round #526 (Div. 2) D. The Fair Nut and the Best Path

    D. The Fair Nut and the Best Path 题目链接:https://codeforces.com/contest/1084/problem/D 题意: 给出一棵树,走不重复的 ...

  7. 用实例工厂的方法实例化bean

    在实例化bean时,除了setter,constructor方法外,还有实例工厂方法,和静态工厂方法. 看代码: People类的代码如下: package com.timo.domain; publ ...

  8. tcp/ip网络协议学习

    链路层介绍 网络层协议的数据单元是 IP 数据报 ,而数据链路层的工作就是把网络层交下来的 IP 数据报 封装为 帧(frame)发送到链路上,以及把接收到的帧中的数据取出并上交给网络层. 以太网 以 ...

  9. tomcat部署多个项目,通过域名解析访问不同的网站

    转摘自:http://qinyinbolan.blog.51cto.com/4359507/1211064 说明: 1.首先需要有多个域名,同时指向一个IP地址. 例如:域名:www.bbb.com, ...

  10. java使用JNA调用dll

    1.自己搞一个dll出来.参考下面链接 http://blog.csdn.net/lqena/article/details/46357165. 2.下载jar jna-4.2.1.jar. 3.复制 ...