如何用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
相关产品推荐
相关产品推荐

