当前位置: 首页 > news >正文

HTTP-大文件传输处理

数据压缩

浏览器在发送请求时都会带着“AcceptEncoding”头字段,里面是浏览器支持的压缩格式列表,例如 gzip、deflate、br 等,这样服务器就可以从中选择一种压缩算法,放进“Content-Encoding”响应头里,再把原数据压缩后发给浏览器。

分块传输

这种“化整为零”的思路在 HTTP 协议里就是“chunked”分块传输编码,在响应报文里用头字段“Transfer-Encoding: chunked”来表示,意思是报文里的 body 部分不是一次性发过来的,而是分成了许多的块(chunk)逐个发送。
“Transfer-Encoding: chunked”和“Content-Length”是不能同时存在的,因为分快传输长度是未知的。
案例-1

@RestController
public class TestController {@GetMapping("/test")void test(HttpServletRequest request, HttpServletResponse response) throws IOException {String s = "hello world";byte[] bytes = s.getBytes();ServletOutputStream outputStream = response.getOutputStream();try {int chunk = 3;int pos = 0;while (pos < bytes.length) {int len = Math.min(chunk, bytes.length - pos);outputStream.write(bytes, pos, len);pos += len;}} catch (Exception e) {e.printStackTrace();}outputStream.flush();}
}

在这里插入图片描述
我们可以看到上面的代码会tomcat会默认加上chunked,因为我们没有设置Content-Length,所以tomcat会认为是分块传输。如果我们设置了Content-Length 我们就会发现不再是chunked分块传输了,但是要注意长度需要和我们的真实数据一致否则会多数据或者丢数据。

response.setContentLength(s.getBytes().length);

范围请求

响应头,告诉客户端支持范围请求:

accept-ranges : bytes

还需要返回这两个信息:

Content-Range: bytes 0-31/96
content-length : 54325

服务器可以发送“AcceptRanges: none”,或者干脆不发送.
请求字段如下:

Range : bytes=76744601-76846440

服务器收到请求以后:

  • 第一,它必须检查范围是否合法,比如文件只有 100 个字节,但请求“200-300”,这就是范围越界了。服务器就会返回状态码416,意思是“你的范围请求有误,我无法处理,请再检查一下”。
  • 第二,如果范围正确,服务器就可以根据 Range 头计算偏移量,读取文件的片段了,返回状态码“206 Partial Content”,和 200 的意思差不多,但表示 body 只是原数据的一部分。
    @GetMapping("/file")void file(HttpServletRequest request, HttpServletResponse response) throws IOException {String s = "hello world! Please give me a lot of money!";response.setHeader("Accept-Ranges", "bytes");byte[] data = s.getBytes();response.setHeader("Content-Length", String.valueOf(data.length));int len = data.length;String header = request.getHeader("Range");if (header == null) {response.setStatus(HttpServletResponse.SC_OK);response.setContentLength(len);response.getOutputStream().write(data);}if (!header.startsWith("bytes=")) {response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);return;}// 去掉 "bytes="header = header.substring(6);String[] parts = header.split("-");int start = 0;int end = len - 1;try {if (!parts[0].isEmpty()) {start = Integer.parseInt(parts[0]);}if (parts.length > 1 && !parts[1].isEmpty()) {end = Integer.parseInt(parts[1]);}} catch (NumberFormatException e) {response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);return;}if (start > end || start < 0 || end >= len) {response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);return;}end = Math.min(end, len - 1);int contentLength = end - start + 1;// 设置部分内容状态码 206response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);// Content-Range: bytes 0-31/96response.setHeader("Content-Range",String.format("bytes %d-%d/%d", start, end,len));// 正确的 Content-Lengthresponse.setHeader("Content-Length", String.valueOf(contentLength));// 返回对应字节ServletOutputStream out = response.getOutputStream();out.write(data, start, contentLength);out.flush();}
}

使用postMan 发送请求:
在这里插入图片描述
收到响应:
在这里插入图片描述

多段数据

请求头如下:

Range : bytes=0-9, 20-29

“multipart/byteranges”,表示报文的 body 是由多段字节序列组成的,并且还要用一个参数“boundary=xxx”给出段之间的分隔标记。

在这里插入图片描述

@GetMapping("/download")public void download(HttpServletRequest request,HttpServletResponse response) throws IOException {String s = "hello world! Please give me a lot of money!";byte[] data = s.getBytes();int dataLen = data.length;String rangeHeader = request.getHeader("Range");if (rangeHeader == null || !rangeHeader.startsWith("bytes=")) {// 没有 Range → 全部文件response.setHeader("Content-Length", String.valueOf(dataLen));response.setContentLength(dataLen);response.getOutputStream().write(data);return;}// 解析多个 Range 范围String rangesPart = rangeHeader.substring("bytes=".length());String[] rangeStrings = rangesPart.split(",");// 多段if (rangeStrings.length > 1) {String boundary = "MY_BOUNDARY";response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);response.setContentType("multipart/byteranges; boundary=" + boundary);ServletOutputStream out = response.getOutputStream();for (String r : rangeStrings) {long[] range = parseRange(r, dataLen);long start = range[0];long end = range[1];long length = end - start + 1;// 头out.println("--" + boundary);out.println("Content-Type: application/octet-stream");out.println("Content-Range: bytes " + start + "-" + end + "/" + dataLen);out.println();// body 数据out.write(data, (int) start, (int) length);out.println();}out.println("--" + boundary + "--");out.flush();return;}// 单段 Rangelong[] range = parseRange(rangeStrings[0], dataLen);long start = range[0];long end = range[1];long length = end - start + 1;response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + dataLen);response.setContentLength((int) length);response.getOutputStream().write(data, (int) start, (int) length);}private long[] parseRange(String range, long totalLen) {range = range.trim();String[] parts = range.split("-");long start = Long.parseLong(parts[0]);long end = parts[1].isEmpty() ? (totalLen - 1) : Long.parseLong(parts[1]);return new long[]{start, end};}

请求:
在这里插入图片描述
响应:
在这里插入图片描述
在这里插入图片描述

参考资料:极客时间透视HTTP

http://www.dtcms.com/a/589069.html

相关文章:

  • [linux仓库]线程同步与生产者消费者模型[线程·陆]
  • 【算法】day17 多维动态规划
  • 网站建设费算什么费用山东青岛网站建设seo优化
  • 【复习】计网每日一题1109---iBGP、AS
  • 30.注意力汇聚:Nadaraya-Watson 核回归
  • 广州营销型网站建设培训班网站设计制作太原
  • RV1126 NO.46:RV1126+OPENCV对视频流进行视频膨胀操作
  • 分布式的cap,base,raft
  • 2025年11月份下半年系统架构师真题(回忆版)
  • C语言刷题-编程(一)(基础)
  • 日常踩用的坑笔记
  • dede制作的网站挂马中国深圳航空公司官网
  • 网站开发工作需要什么专业织梦如何做网站
  • Java 面向对象进阶:抽象类、接口与 Comparable 接口
  • springboot移动端购物系统设计与实现(代码+数据库+LW)
  • 说一下Redis为什么快
  • web网页开发,在线%台球俱乐部管理%系统,基于Idea,html,css,jQuery,jsp,java,ssm,mysql。
  • 【C++STL】入门不迷路:容器适配器 + deque+stack/queue 使用 + 模拟实现指南!
  • 做设计挣钱的网站备案的网站有什么好处
  • 项目环境变量配置全攻略
  • AIGC|深圳AI优化企业新榜单与选择指南
  • 小红书MCP服务器 - 技术架构深度解析
  • 003-HTML之表单
  • 湖南省网站集约化建设实施方案做网站里面的图片像素要求
  • x402 生态系统:Web3 与 AI 融合的支付新基建
  • Rust 练习册 :掌握文本处理与词频统计
  • SpringCloud01-初识微服务SpringCloud
  • Web3 与去中心化应用(dApp)学习分享:从基础到应用
  • 贵州省住房和城乡建设厅官网站首页本地如何安装wordpress
  • 使用 dash 构建整洁架构应用