fix: 修复 HEAD 无法获取 Content-Length 导致选流降级的问题

This commit is contained in:
RrOrange
2026-01-29 15:27:19 +08:00
committed by GitHub
parent 8c5cb7fa5c
commit 4bfe2df405

View File

@@ -746,24 +746,61 @@ impl BiliClient {
}
pub async fn get_content_length(&self, media_url: &str) -> anyhow::Result<u64> {
let request = self.content_length_client.read().head(media_url);
let http_resp = request.send().await?;
// 检查http响应状态码
let status = http_resp.status();
if status != StatusCode::OK {
return Err(anyhow!("预料之外的状态码({status})"));
fn parse_content_length(headers: &HeaderMap) -> anyhow::Result<u64> {
headers
.get("Content-Length")
.context("缺少 Content-Length 响应头")?
.to_str()
.context("Content-Length 响应头无法转换为字符串")?
.parse::<u64>()
.context("Content-Length 响应头无法转换为整数")
}
let headers = http_resp.headers();
let content_length = headers
.get("Content-Length")
.context("缺少 Content-Length 响应头")?
.to_str()
.context("Content-Length 响应头无法转换为字符串")?
.parse::<u64>()
.context("Content-Length 响应头无法转换为整数")?;
fn parse_total_from_content_range(headers: &HeaderMap) -> anyhow::Result<u64> {
// Example: "bytes 0-0/12345"
let content_range = headers
.get("Content-Range")
.context("缺少 Content-Range 响应头")?
.to_str()
.context("Content-Range 响应头无法转换为字符串")?;
Ok(content_length)
let Some((_, total)) = content_range.split_once('/') else {
return Err(anyhow!("预料之外的 Content-Range 格式: {content_range}"));
};
total
.parse::<u64>()
.context("Content-Range 总大小无法转换为整数")
}
// 优先使用 HEAD 获取 Content-Length
let request = self.content_length_client.read().head(media_url);
let http_resp = request.send().await?;
let status = http_resp.status();
if status == StatusCode::OK {
if let Ok(content_length) = parse_content_length(http_resp.headers()) {
return Ok(content_length);
}
}
// 部分 upos/CDN 对 HEAD 支持不完整(尤其是高码率/高帧率流),这里降级用 Range 请求探测总大小
let request = self
.content_length_client
.read()
.get(media_url)
.header("range", "bytes=0-0");
let http_resp = request.send().await?;
let status = http_resp.status();
if status == StatusCode::PARTIAL_CONTENT {
return parse_total_from_content_range(http_resp.headers());
}
if status == StatusCode::OK {
return parse_content_length(http_resp.headers());
}
Err(anyhow!("预料之外的状态码({status})"))
}
pub async fn get_url_with_content_length(&self, urls: Vec<String>) -> Vec<(String, u64)> {