1. http 请求报文的组成:
      1. 请求行 request line
      2. 请求头 request header
      3. 空行 Blank Line
      4. 请求体 request body
    2. 请求行
      1. 示例:GET /index.html HTTP/1.1
      2. 包含的信息:
        1. 请求方法 GET
        2. 请求路径 /index.html
        3. http 版本 HTTP/1.1

    http 消息结构 - 图1

    1. 请求头
      1. 包含了一系列的头部字段。
      2. 每一个字段都是由字段名和字段值组成,两者之间用冒号分隔。
      3. 每一个字段都描述了关于请求的一些附加信息
      4. 一些常见的请求头字段:
        1. Host 用于指定请求资源的服务器和端口号
        2. User-Agent 描述客户端的软件和软件版本
        3. Accept 客户端能处理的媒体类型
        4. Content-Length 请求主体的长度,单位为字节
    2. 空行
      1. 请求头部和消息主体之间有一个空行。
      2. 空行是一个必须的分隔,它标示了头部字段的结束。
    3. 请求体
      1. 不是所有的 HTTP 请求都有主体。例如,GET 请求通常没有主体,但 POST 请求可能会带有主体,该主体包含了表单数据或 JSON 数据等。
      2. 请求主体中的数据格式通常由 Content-Type 头部指定。
    4. http 请求报文主要包括请求行、请求头部、一个空行和可能存在的请求主体
      1. 注意,对于一个合法的请求报文而言,前 3 者都是必须的,请求主体可以为空。
      2. 尤其注意请求头结束后要有一个空行,这个空行是不能省略的,即便是在请求体为空的情况下。
    1. // server.js
    2. const http = require('http');
    3. const server = http.createServer((req, res) => {
    4. res.writeHead(200, { 'Content-Type': 'application/json' });
    5. res.end(`{"msg": "hello world"}`);
    6. });
    7. server.listen(8888, () => {
    8. console.log('Server running on port 8888');
    9. })

    基于 nodejs 的 http 模块,实现一个本地服务

    1. // client.js
    2. const net = require('net');
    3. const client = net.createConnection({ port: 8888 }, () => {
    4. // 'connect' listener
    5. console.log('connected to server!');
    6. client.write('GET / HTTP/1.1\r\n');
    7. client.write('Host: localhost:8888\r\n');
    8. client.write('\r\n');
    9. });
    10. client.on('data', (data) => {
    11. console.log('\n\n[data from server]:\n\n');
    12. console.log(data.toString())
    13. client.end(); // close the connection after receiving data
    14. });
    15. client.on('end', () => {
    16. console.log('disconnected from server');
    17. });
    18. /*
    19. connected to server!
    20. [data from server]:
    21. HTTP/1.1 200 OK
    22. Content-Type: application/json
    23. Date: Mon, 14 Aug 2023 02:03:53 GMT
    24. Connection: keep-alive
    25. Keep-Alive: timeout=5
    26. Transfer-Encoding: chunked
    27. 16
    28. {"msg": "hello world"}
    29. 0
    30. disconnected from server
    31. */

    基于 nodejs 的 net 模块,手写 http 请求报文,请求本地服务

    对于请求报文的书写,有很多种方式,只要满足 http 请求报文的格式要求即可。

    1. // 下面这些写法即可
    2. client.write('GET / HTTP/1.1\r\n');
    3. client.write('Host: localhost:8888\r\n');
    4. client.write('\r\n');
    5. client.write(`GET / HTTP/1.1\r\nHost: localhost:8888\r\n\r\n`);
    6. client.write(`GET / HTTP/1.1\r
    7. Host: localhost:8888\r
    8. \r
    9. `)

    需要注意的是:

    • 模板字符串中我们如果使用了换行,相当于在结尾默认插入了一个字符 \n,不要忘记补上回车符 \r
    • 请求头信息结束位置,不要忘记加上空行
    1. http 响应报文的组成:
      1. 响应行 response line
      2. 响应头 response header
      3. 响应体 response body

    http 消息结构 - 图2

    1. // server_net.js
    2. const net = require('net');
    3. const server = net.createServer(socket => {
    4. socket.on('data', data => {
    5. // 这里仅仅简单地判断了数据是否包含 GET 方法来做出响应,实际应用应该有完整的 HTTP 解析过程。
    6. if (data.toString().startsWith('GET')) {
    7. const response = `HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{"msg": "hello world"}`;
    8. socket.write(response);
    9. socket.end(); // 关闭连接
    10. }
    11. });
    12. socket.on('error', err => {
    13. console.error('Socket error:', err);
    14. });
    15. });
    16. server.listen(8888, () => {
    17. console.log('Server running on port 8888');
    18. });

    基于 nodejs 的 net 模块,实现一个本地服务。

    • 解析 http 请求
    • 手写响应报文
    1. // client.js
    2. const net = require('net');
    3. const client = net.createConnection({ port: 8888 }, () => {
    4. // 'connect' listener
    5. console.log('connected to server!');
    6. client.write('GET / HTTP/1.1\r\n');
    7. client.write('Host: localhost:8888\r\n');
    8. client.write('\r\n');
    9. });
    10. client.on('data', (data) => {
    11. console.log('\n\n[data from server]:\n\n');
    12. console.log(data.toString())
    13. client.end(); // close the connection after receiving data
    14. });
    15. client.on('end', () => {
    16. console.log('disconnected from server');
    17. });
    18. /*
    19. connected to server!
    20. [data from server]:
    21. HTTP/1.1 200 OK
    22. Content-Type: application/json
    23. {"msg": "hello world"}
    24. disconnected from server
    25. */

    也可以用浏览器直接请求 http://localhost:8888/,获取到的内容如下:

    image.png