Node.js代码实例:简单Web服务端

前言

Node.js代码实例:简单Web服务端。


代码仓库


为什么要写一份Node.js简单Web服务端的代码实例?

  • 想多了解一些技术知识,所以简单学习了Node.js
  • 写过C和C++的环境和网络编程,它们的处理很复杂。了解到Node.js底层使用Libuv网络异步I/O库,以事件驱动+异步I/O方式运行,适合处理网络I/O高并发的场景,和Go语言相似,具有互相比对的学习价值
  • 写过而且写的很多代码都是客户端/服务端(C/S)模型的网络传输,写一份关于Web服务端的传输,能够深入了解Web服务和HTTP原理

内容

  • 详细解析创建http服务端的流程、URL的组成、请求消息的结构和响应消息的结构
  • 通过网络传输,浏览器客户端向该Web服务端发送“GET”请求,服务端依据URL响应本地相应的HTML、CSS和JavaScript文件,并在客户端渲染显示页面

目录结构

simple_Web_server目录:

  • server.js文件
  • www目录

www目录:

  • index.html
  • index.css
  • index.js
  • value.html

代码

server.js

// 一、导入http模块
const http_module = require('http')    // HTTP相关
const path_module = require('path') // 字符串路径相关
const fs_module = require('fs')    // 文件系统相关

// 二、创建服务端对象
// 参数:可选项服务端如timeout和keepalive等配置,自动添加到‘request’请求事件的回调函数:当有客户端发起请求时,调用这个回调函数
// 返回值:http.server对象
const server = http_module.createServer()

const host = '127.0.0.1'    // 主机
const port = 8000   // 端口
const request_query_stringing_key = 'key'   // 请求url中,查询字符串的键
const site_root_directory = 'www'   // 网站根目录

// 三、服务端对象绑定‘request’请求事件,监听客户端请求
// emitter.on(eventName, listener)是node.js中的事件绑定方法
// 当有客户端发起请求时,调用这个回调函数:传入http.IncomingMessage请求对象和http.ServerResponse响应对象
server.on('request', (request, response) => {
    // 1. 获取http请求信息
    // http请求有3部分:请求行,请求头和请求体
    // 请求行有3部分:方法,url,http版本
    // (1)获取方法:“GET”,这里不需要
    // const request_method = request.method
    // (1)获取url:“/index.html?key=value”
    const request_url = request.url
    // (1)获取版本:“1.1”,这里不需要
    // const request_version = request.httpVersion   
    // (2)获取请求头,返回键值对object,这里不需要
    // const request_headers = request.headers 
    // (3)获取请求体,返回string。GET方法请求体一般为空,这里不需要
    // let request_body = ''
    // request.on('data', (chunk) => { // 请求绑定‘data’事件,数据按流传输,有数据时读取chunk为Buffer对象,自动转换为string
    //     request_body += chunk
    // })
    // request.on('end', () => { // 请求绑定‘end’事件,数据传输完成时触发
    //     console.log(request_body)
    // })

    //  2. 处理url。如http://127.0.0.1:8000/index.html?key=value
    // url有4部分:协议“http://”,地址主机名和端口“127.0.0.1:8000”,路径“/index.html”,查询字符串“?key=value”
    // (1)获取协议http,这里不需要
    // (2) 获取地址,这里不需要
    const absolute_url = 'http://' + host + ':' + port + request_url    // 获取请求的绝对url。如http://127.0.0.1:8000/index.html?key=value
    const request_path_query_string = new URL(absolute_url)  // 解析绝对url,获取路径和查询字符串。如:/index.html?key=value
    // (3)获取路径。如:/index.html
    const request_path = request_path_query_string.pathname
    // (4)获取查询字符串。返回object如:{'key' => 'value'}
    const request_query_string = request_path_query_string.searchParams
    const request_query_string_value = request_query_string.get(request_query_stringing_key)    // 获取查询字符串的值。如:通过'key'获取'value'

    // 3. 结合网络路径和查询字符串,映射为本地文件系统中的路径
    let fs_path = ""
    if (request_path === '/') {
        fs_path = path_module.join(__dirname, site_root_directory, "index.html")
        // 对于url为'/'的网络路径,映射为服务端js文件所在当前目录下,网站根目录下的index.html文件路径
        // 如:C:\Users\DSHH\Desktop\simple_Web_server\www\index.html
    } else if (request_path === '/index.html' && request_query_string_value === 'value') {
        fs_path = path_module.join(__dirname, site_root_directory, "value.html")
        // 对于url为'/index.html'的网络路径,查询字符串值为'value',映射为服务端js文件所在当前目录下,网站根目录下的value.html文件路径
        // 如:C:\Users\DSHH\Desktop\simple_Web_server\www\value.html
    } else {
        fs_path = path_module.join(__dirname, site_root_directory, request_path)
        // 对于其他网络路径,映射为服务端js文件当前目录下,网站根目录下的资源文件路径
        // 如url为:'/other.html',则本地路径为:如:C:\Users\DSHH\Desktop\simple_Web_server\www\other.html
        // 注意:对于其他资源如css、js、ico等请求,全都走这个分支
        // 如:C:\Users\DSHH\Desktop\simple_Web_server\www\index.css、C:\Users\DSHH\Desktop\simple_Web_server\www\favicon.ico
        // 注意:浏览器除了请求路径中的页面,可能会自动请求favicon.ico作为网页的图标,可不管
    }

    // 4. 读取本地文件系统相应的文件,设置http响应信息
    // http响应有3部分:响应行,响应头和响应体
    // 响应行有3部分:http版本,状态码,状态描述
    //(1) http版本,无需设置
    // (2) 状态码在下面读取文件时设置
    // (3) 状态描述无需设置,一般与状态码匹配
    // response.statusMessage = 'This is status message'
    // (4) 响应头
    // 注意:
    // 只需要依据文档类型设置mime类型让浏览器可以解析html、css和js文档
    // 否则当html、css、js分文件编写时,请求html会再次请求css和js文档,再次进入这个回调函数
    // 若mime类型为text/html,则无法解析css文档,css无法渲染
    // 设置编码为utf8支持中文显示不乱码
    const fs_path_ext_name = path_module.extname(fs_path) // 获取本地路径文件的扩展名,如:.css
    const fs_path_mime_type = fs_path_ext_name.slice(1)   // 获取mime类型中,text类型下的子类型名,如:css
    response.setHeader('content-type', `text/${fs_path_mime_type};charset=utf-8`)   // 拼接为:text/css;charset=utf-8
    // (5) 响应体,在下面读取文件时设置

    // 参数:文件路径和编码等可选项,回调函数
    // 当读取完成时,调用这个回调函数:传入错误Error和数据string对象
    fs_module.readFile(fs_path, 'utf8', (error, data) => {
        // 如果有错误,返回404资源不存在状态码和状态信息
        // 没有错误,返回读取的文件数据
        if (error) {
            response.statusCode = 404   // (2)设置状态码
            // 参数:流数据,可选项编码和回调函数
            // 返回值:bool,不需要
            response.write('<h1>404 未找到</h1>')   // (5)设置响应体
            // 参数:数据、编码和回调函数等可选项
            // 返回值:this,即end()的调用者response对象
            // 对每个响应可以调用多次write()写入数据,必须调用一次end()返回响应
            response.end()
        } else {
            response.statusCode = 200   // (2)设置状态码
            response.write(data)    // (5)设置响应体
            response.end()
        }
    })
})

// 四、启动服务端监听
// 参数:对于TCP,使用端口、地址、半连接和全连接队列和回调函数可选项
server.listen(port, host, () => {
    console.log(`Wen服务端运行在: http://${host}:${port}`)
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <h1>这是index.html</h1>

    <script src="./index.js"></script>
</body>
</html>

index.css

h1 {
    color: blue;
}

index.js

alert('这是index.js')

value.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>这是value.html</h1>
</body>

</html>

结果

运行Web服务端:

PS C:\Users\DSHH\Desktop\simple_Web_server> node server.js
Wen服务端运行在: http://127.0.0.1:8000

浏览器访问: http://127.0.0.1:8000/ 或 http://127.0.0.1:8000/index.html

在这里插入图片描述
在这里插入图片描述

浏览器访问: http://127.0.0.1:8000/index.html?key=value

在这里插入图片描述

浏览器访问: http://127.0.0.1:8000/other.html

在这里插入图片描述


总结

Node.js代码实例:简单Web服务端。


参考资料


作者的话

  • 感谢参考资料的作者/博主
  • 作者:夜悊
  • 版权所有,转载请注明出处,谢谢~
  • 如果文章对你有帮助,请点个赞或加个粉丝吧,你的支持就是作者的动力~
  • 文章在描述时有疑惑的地方,请留言,定会一一耐心讨论、解答
  • 文章在认识上有错误的地方, 敬请批评指正
  • 望读者们都能有所收获

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值