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

如何用Dart的http.Response从Content-Disposition头提取UTF-8文件名

问题描述

我通过GET请求从服务器下载文件,代码如下:

import 'package:http/http.dart' as http;

final http.Response response = await http.get(uri, headers: headers);
if (response.isOk()) {
  response.headers.forEach((key, value) {
    print('key = $key; value = $value');
  });

  final Uint8List bytes = response.bodyBytes;

  AnchorElement(href: "$contentPrefix${base64Encode(bytes)}")
    ..setAttribute("download", "file.xlsx")
    ..click();
} else {
  print('report request status code is ${response.statusCode}');
}

我需要获取包含在Content-Disposition头中的UTF-8编码文件名,但这个头并未出现在http.Response.headers中,请问该如何提取?

解决方案

1. 先确认Content-Disposition头是否存在

部分HTTP客户端会自动转换头字段的大小写,你可以尝试用不同大小写的键直接获取:

// 尝试多种大小写形式的键
String? dispositionHeader = response.headers['content-disposition'] ?? 
                            response.headers['Content-Disposition'] ??
                            response.headers['CONTENT-DISPOSITION'];

如果能拿到该字段,再进行下一步解析。

2. 解析UTF-8编码的文件名

Content-Disposition的典型格式为:

attachment; filename="默认文件名.xlsx"; filename*=UTF-8''%E6%96%87%E4%BB%B6%E5%90%8D.xlsx

其中filename*字段对应UTF-8编码的文件名,可通过正则提取并解码:

if (dispositionHeader != null) {
  // 匹配filename*=UTF-8''后的URL编码内容
  RegExp utf8FilenameRegex = RegExp(r'filename\*=UTF-8\'\'(.*)');
  Match? utf8Match = utf8FilenameRegex.firstMatch(dispositionHeader);
  
  if (utf8Match != null) {
    String encodedFilename = utf8Match.group(1)!;
    // URL解码得到原始UTF-8文件名
    String decodedFilename = Uri.decodeComponent(encodedFilename);
    // 替换硬编码的文件名
    AnchorElement(href: "$contentPrefix${base64Encode(bytes)}")
      ..setAttribute("download", decodedFilename)
      ..click();
  } else {
    // 降级处理普通filename字段
    RegExp normalFilenameRegex = RegExp(r'filename="(.*)"');
    Match? normalMatch = normalFilenameRegex.firstMatch(dispositionHeader);
    if (normalMatch != null) {
      String filename = normalMatch.group(1)!;
      AnchorElement(href: "$contentPrefix${base64Encode(bytes)}")
        ..setAttribute("download", filename)
        ..click();
    }
  }
}

3. 处理客户端头过滤问题

如果上述方法仍无法获取Content-Disposition头,可能是http客户端库自动过滤了部分头。可以尝试使用底层HttpClient发起请求,直接获取所有响应头:

import 'dart:io';

HttpClient client = HttpClient();
HttpClientRequest request = await client.getUrl(uri);
// 添加自定义请求头
headers.forEach((key, value) {
  request.headers.add(key, value);
});
HttpClientResponse response = await request.close();

// 整理所有响应头为键值对
Map<String, String> allHeaders = {};
response.headers.forEach((key, values) {
  allHeaders[key] = values.join('; ');
});

String? dispositionHeader = allHeaders['content-disposition'];
// 后续解析步骤同上述第2步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:59:54