You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust Actix配置分片下载时Content Length始终为0的问题求助

问题

我正在使用react-pdf 9.1.0在浏览器中展示PDF,希望实现分片下载功能。原本服务端采用OpenResty,参考pdf.js文档后,添加了如下Rust Actix服务端代码以支持分片加载:

// tell the client support slice loading
return HttpResponse::PartialContent()
    .insert_header(CacheControl(vec![CacheDirective::NoCache]))
    .append_header(("Accept-Ranges", "bytes"))
    .append_header((
        "Access-Control-Expose-Headers",
        "Accept-Ranges,Content-Range",
    ))
    .append_header(("Content-Encoding", "identity"))
    .append_header(("Content-Length", content_length))
    .content_type("application/pdf")
    .body("");

但发现即使已设置Content-Length,响应的内容长度始终为0,且已确认content_length变量值大于0。请问该问题原因是什么?应如何修复?是否需要将内容放入body?另外,我仅希望告知客户端服务端支持分片下载,若文件过大(>500MB),将内容放入body无法减少网络传输量,与传输整个文件无区别。

回答

问题原因

  1. 响应体为空覆盖头信息:你设置了Content-Length头,但返回的body("")是空字符串,浏览器会以实际传输的响应体长度为准,直接忽略你手动设置的Content-Length,因此显示内容长度为0。
  2. 违背HTTP 206响应规范:206 Partial Content是用来返回具体分片内容的响应码,不能仅返回头信息而不带对应分片的body,这种写法不符合HTTP协议要求。

修复方案

要实现分片下载,需要根据请求类型和请求头分场景处理:

1. 处理HEAD请求(仅告知客户端支持分片)

react-pdf通常会先发送HEAD请求获取文件元信息,此时只需返回文件总长度和支持分片的头,无需传输文件内容:

use actix_web::{HttpResponse, http::header::{CacheControl, CacheDirective}};

// 处理HEAD请求
return HttpResponse::Ok()
    .insert_header(CacheControl(vec![CacheDirective::NoCache]))
    .append_header(("Accept-Ranges", "bytes"))
    .append_header((
        "Access-Control-Expose-Headers",
        "Accept-Ranges,Content-Range",
    ))
    .append_header(("Content-Length", content_length))
    .content_type("application/pdf")
    .body("");

2. 处理带Range头的GET请求(返回具体分片)

当客户端发送带有Range头的GET请求时(比如Range: bytes=0-1023),需要解析请求的范围,读取对应文件片段后返回:

use actix_web::{HttpResponse, http::header::{CacheControl, CacheDirective, ContentRange, ByteRangeSpec}};
use std::fs::File;
use std::io::Read;

// 解析Range头(示例逻辑,需根据实际情况完善错误处理)
let range_str = req.headers().get("Range").unwrap().to_str().unwrap();
let (start, end) = parse_range(range_str, content_length);
let chunk_len = end - start + 1;

// 读取文件对应分片
let mut file = File::open("path/to/target/pdf").unwrap();
file.seek(std::io::SeekFrom::Start(start)).unwrap();
let mut chunk = vec![0; chunk_len as usize];
file.read_exact(&mut chunk).unwrap();

// 返回206分片响应
return HttpResponse::PartialContent()
    .insert_header(CacheControl(vec![CacheDirective::NoCache]))
    .append_header(("Accept-Ranges", "bytes"))
    .append_header((
        "Access-Control-Expose-Headers",
        "Accept-Ranges,Content-Range",
    ))
    .append_header(("Content-Length", chunk_len.to_string()))
    .insert_header(ContentRange::Bytes(ByteRangeSpec::FromTo(start, end), Some(content_length)))
    .content_type("application/pdf")
    .body(chunk);

3. 处理不带Range头的GET请求

如果客户端发送不带Range的GET请求,有两种可选处理方式:

  • 返回整个文件(200 OK),同时带上Accept-Ranges: bytes头,后续客户端会自动触发分片请求;
  • 返回416 Requested Range Not Satisfiable,强制客户端使用分片请求(需确保客户端支持该逻辑)。

大文件传输的顾虑解决

完全不需要返回整个文件来告知客户端支持分片:

  • 通过处理HEAD请求,仅返回文件元信息(总长度、支持分片的头),不会传输任何文件内容;
  • 客户端收到HEAD响应后,会自动发送分片请求获取所需的PDF片段,从根源上避免大文件一次性传输的问题。

内容的提问来源于stack exchange,提问作者Dolphin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 15:32:09