网络与协议 · 33/72
1. Ajax、Axios、Fetch 对比 2. Ajax 原理 3. Ajax 技术与实现 4. 常见的应用层协议 5. 浏览器缓存的存储位置 6. 从输入 URL 到页面显示的过程 7. Cache-Control 常见配置值 8. CDN 工作原理 9. 为什么推荐将静态资源放到 CDN 上 10. Cookie 的弊端 11. Cookie 的 Secure 属性设置 12. CORS 请求携带身份凭证的方法 13. CORS 跨域原理 14. 复杂请求预检检查内容 15. CORS 预检请求 16. CORS简单请求的条件 17. 简单请求为何无需预检 18. DNS 域名解析与网络请求路由 19. 什么是跨域 20. 什么是 DNS 劫持? 21. DNS 预解析优化网页加载速度 22. DNS 解析过程与优化 23. URL 参数为什么需要 encodeURIComponent 转码 24. Last-Modified 和 ETag 的区别 25. Fetch 发送两次请求的原因 26. 正向代理与反向代理 27. 前后端通信方式 28. GET请求能否上传图片 29. GET 请求的传参长度限制 30. HTTP 缓存策略 31. GET 与 POST 的区别 32. HTTP状态码301与302的区别 33. HTTP 数据传输 34. HTTP 队头阻塞 35. HTTP 请求头和响应头的重要字段 36. HTTP发展历程 37. HTTP与HTTPS总结 38. HTTP 和 HTTPS 的区别 39. HTTP 报文结构与状态码 40. HTTP Keep-Alive 机制 41. HTTP管道机制的作用 42. HTTP协议优缺点 43. HTTP 重定向状态码 301/302/303/307/308 44. HTTP 请求方法 45. HTTP 协议版本演进 46. HTTP与TCP的区别 47. HTTP/2 多路复用原理 48. HTTPS 协议的缺点 49. HTTP/3 如何保证传输可靠性 50. HTTP/2 的改进 51. HTTPS 加密原理 52. 什么是负载均衡? 53. Nginx 负载均衡调度算法 54. Nginx 是什么 55. 对象存储 OSS 是什么 56. OPTIONS 请求方法及使用场景 57. 轮询与 WebSocket 对比 58. HTTPS 中 SSL 的 OSI 层位置 59. SSL连接恢复 60. 强缓存和协商缓存 61. TCP 三次握手与四次挥手 62. TCP三次握手中的数据传输 63. TCP 和 HTTP 请求的关系 64. TCP/IP 协议 65. TCP 如何判断丢包 66. TCP 与 UDP 的区别 67. WebSocket 的 Handshaking 握手过程 68. TLS 1.3 相比 TLS 1.2 的改进 69. URI、URL、URN 的区别 70. WebSocket 心跳机制 71. WebSocket 协议原理 72. XML与JSON对比

HTTP 数据传输

HTTP 中定长、分块、压缩、范围请求等数据传输方式

问题

HTTP 协议中有哪些数据传输方式?各自的应用场景是什么?

解答

1. 定长传输

通过 Content-Length 指定响应体的字节长度。

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12

Hello World!

服务端示例:

const http = require('http')

http.createServer((req, res) => {
  const body = 'Hello World!'
  // 设置 Content-Length
  res.setHeader('Content-Length', Buffer.byteLength(body))
  res.end(body)
}).listen(3000)

2. 分块传输

当响应体长度未知时,使用 Transfer-Encoding: chunked 分块发送。

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

7\r\n
Hello, \r\n
6\r\n
World!\r\n
0\r\n
\r\n

服务端示例:

const http = require('http')

http.createServer((req, res) => {
  res.setHeader('Transfer-Encoding', 'chunked')
  
  // 分块写入数据
  res.write('Hello, ')
  
  setTimeout(() => {
    res.write('World!')
    res.end() // 发送结束标记 0\r\n\r\n
  }, 1000)
}).listen(3000)

3. 压缩传输

通过 Content-Encoding 指定压缩算法,减少传输体积。

常见压缩算法:

  • gzip - 最常用
  • deflate - 较少使用
  • br - Brotli,压缩率更高
const http = require('http')
const zlib = require('zlib')

http.createServer((req, res) => {
  const acceptEncoding = req.headers['accept-encoding'] || ''
  const body = 'Hello World!'.repeat(100)
  
  if (acceptEncoding.includes('gzip')) {
    res.setHeader('Content-Encoding', 'gzip')
    res.end(zlib.gzipSync(body))
  } else if (acceptEncoding.includes('br')) {
    res.setHeader('Content-Encoding', 'br')
    res.end(zlib.brotliCompressSync(body))
  } else {
    res.end(body)
  }
}).listen(3000)

4. 范围请求

支持断点续传和分片下载,通过 Range 请求头指定范围。

# 请求
GET /video.mp4 HTTP/1.1
Range: bytes=0-1023

# 响应
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/10240
Content-Length: 1024

服务端示例:

const http = require('http')
const fs = require('fs')
const path = require('path')

http.createServer((req, res) => {
  const filePath = './video.mp4'
  const stat = fs.statSync(filePath)
  const fileSize = stat.size
  const range = req.headers.range
  
  if (range) {
    // 解析 Range: bytes=start-end
    const [start, end] = range
      .replace('bytes=', '')
      .split('-')
      .map((n, i) => n ? parseInt(n) : (i === 0 ? 0 : fileSize - 1))
    
    res.writeHead(206, {
      'Content-Range': `bytes ${start}-${end}/${fileSize}`,
      'Content-Length': end - start + 1,
      'Accept-Ranges': 'bytes'
    })
    
    fs.createReadStream(filePath, { start, end }).pipe(res)
  } else {
    res.writeHead(200, {
      'Content-Length': fileSize,
      'Accept-Ranges': 'bytes'
    })
    fs.createReadStream(filePath).pipe(res)
  }
}).listen(3000)

5. 多部分传输

用于表单文件上传,Content-Type: multipart/form-data

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain

文件内容
------WebKitFormBoundary--

前端上传示例:

// 使用 FormData 上传文件
const form = new FormData()
form.append('file', fileInput.files[0])
form.append('name', 'test')

fetch('/upload', {
  method: 'POST',
  body: form // 浏览器自动设置 Content-Type 和 boundary
})

关键点

  • 定长传输Content-Length 指定确切字节数,适用于已知长度的响应
  • 分块传输Transfer-Encoding: chunked,适用于动态生成、长度未知的内容
  • 压缩传输Content-Encoding 配合 gzip/br,显著减少传输体积
  • 范围请求Range + 206 状态码,支持断点续传和视频拖拽播放
  • 多部分传输multipart/form-data,用于文件上传和混合数据提交