使用Flutter Dio调用文件API时遇406错误的解决与疑问
406错误的根本原因与通用解决办法
根本原因
- 自研API的Content-Type校验逻辑:你的API对上传文件的Content-Type存在严格限制,仅接受
application/x-tar类型。而Flutter Dio默认会根据文件扩展名推断Content-Type,若其内置的MIME类型映射表中未正确关联.tar文件与application/x-tar,就会发送不符合API要求的Content-Type,触发406错误。 - Postman与Dio的MIME推断差异:Postman会自动识别.tar文件并设置正确的
application/x-tar类型,而Dio的默认推断规则不匹配API要求,导致请求不被接受。 - 406错误的本质误解:虽然406字面意思是服务器无法生成匹配Accept头的响应,但实际场景中是你的API将上传文件的Content-Type纳入了可接受范围校验,后端逻辑把文件类型和请求合法性绑定,导致不符合的请求被拒绝。
通用解决办法
方法一:直接指定单个文件的Content-Type
无需传递冗余的file_tar字段,仅给目标文件字段指定API认可的Content-Type即可:
var dio = Dio(); var formData = FormData.fromMap({ 'file': await MultipartFile.fromFile( file.path, contentType: MediaType('application', 'x-tar') ), }); var response = await dio.post(url, data: formData, options: Options(headers: { 'Accept': '*/*', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate, br', }), onSendProgress: (int sent, int total) { var progress = (sent / total) * 100; log('Progress: $progress %'); });
注意:无需手动设置
Content-Type: multipart/form-data,Dio在发送FormData时会自动生成正确的Content-Type(包含boundary),手动设置反而可能导致格式错误。
方法二:扩展Dio的默认MIME类型映射
如果需要上传多种类型文件,不想每次手动指定Content-Type,可以自定义Dio的MIME解析规则:
// 初始化Dio前添加自定义MIME映射 DioMixin.mimeTypeResolver.addResolver((path) { if (path.endsWith('.tar')) { return MediaType('application', 'x-tar'); } // 可添加其他文件类型的映射,比如.zip if (path.endsWith('.zip')) { return MediaType('application', 'zip'); } return null; // 未匹配时回退到默认解析逻辑 }); var dio = Dio(); // 后续使用MultipartFile.fromFile时无需手动指定contentType var formData = FormData.fromMap({ 'file': await MultipartFile.fromFile(file.path), });
方法三:调整自研API的校验逻辑
如果API不需要严格限制文件Content-Type,可修改后端代码:
- 忽略文件的Content-Type校验,仅校验文件本身的格式;
- 允许接收通用二进制类型
application/octet-stream,兼容更多客户端的请求。
PHP端解决办法
PHP上传时需确保文件字段携带正确的Content-Type,使用CURL的CURLFile对象指定类型:
$filePath = '/path/to/your/file.tar'; $curlFile = new CURLFile($filePath, 'application/x-tar', 'file'); $postData = ['file' => $curlFile]; $ch = curl_init($apiUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch);
内容的提问来源于stack exchange,提问作者tomDev
相关产品推荐
相关产品推荐

