使用 xUtils 上传文件至阿里云 OSS 时遇到的错误

项目中使用 xUtils,在上传 OSS 时遇到问题,参数全都正确,但服务器却返回“400 Bad request”错误。
用 Fiddler 比对正常的请求,发现上传失败时的 RequestBody 中每一项,除了文件 file 以外,都多了 Content-Type: text/plain; charset=UTF-8Content-Transfer-Encoding: 8bit 这两项。
阿里云 OSS 服务端返回的 ErrorCode:400 MalformedPOSTRequest “Post 请求的 body 格式非法”。提示:The body of your POST request is not well-formed multipart/form-data
文件 file 需要 Content-Type: image/png,至于 Content-Transfer-Encoding: binary 可有可无。

尝试移除上述两个参数后,上传请求被正常接受。
/src/com/lidroid/xutils/http/client/multipart/FormBodyPart.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.lidroid.xutils.http.client.multipart;
import com.lidroid.xutils.http.client.multipart.content.ContentBody;
public class FormBodyPart {
private final String name;
private final MinimalFieldHeader header;
private final ContentBody body;
public FormBodyPart(final String name, final ContentBody body) {
super();
if (name == null) {
throw new IllegalArgumentException("Name may not be null");
}
if (body == null) {
throw new IllegalArgumentException("Body may not be null");
}
this.name = name;
this.body = body;
this.header = new MinimalFieldHeader();
generateContentDisposition(body);
generateContentType(body);
// generateTransferEncoding(body); // 改动一:注释掉,不然无法上传到OSS。
}
public FormBodyPart(final String name, final ContentBody body, final String contentDisposition) {
super();
if (name == null) {
throw new IllegalArgumentException("Name may not be null");
}
if (body == null) {
throw new IllegalArgumentException("Body may not be null");
}
this.name = name;
this.body = body;
this.header = new MinimalFieldHeader();
if (contentDisposition != null) {
addField(MIME.CONTENT_DISPOSITION, contentDisposition);
} else {
generateContentDisposition(body);
}
generateContentType(body);
// generateTransferEncoding(body); // 改动二:注释掉,不然无法上传到OSS。
}
public String getName() {
return this.name;
}
public ContentBody getBody() {
return this.body;
}
public MinimalFieldHeader getHeader() {
return this.header;
}
public void addField(final String name, final String value) {
if (name == null) {
throw new IllegalArgumentException("Field name may not be null");
}
this.header.addField(new MinimalField(name, value));
}
protected void generateContentDisposition(final ContentBody body) {
StringBuilder buffer = new StringBuilder();
buffer.append("form-data; name=\"");
buffer.append(getName());
buffer.append("\"");
if (body.getFilename() != null) {
buffer.append("; filename=\"");
buffer.append(body.getFilename());
buffer.append("\"");
}
addField(MIME.CONTENT_DISPOSITION, buffer.toString());
}
protected void generateContentType(final ContentBody body) {
StringBuilder buffer = new StringBuilder();
buffer.append(body.getMimeType()); // MimeType cannot be null
if (body.getCharset() != null) { // charset may legitimately be null
buffer.append("; charset=");
buffer.append(body.getCharset());
return; // 改动三:如果非空就返回,这样file的ContentType任然是保留的。
}
addField(MIME.CONTENT_TYPE, buffer.toString());
}
protected void generateTransferEncoding(final ContentBody body) {
addField(MIME.CONTENT_TRANSFER_ENC, body.getTransferEncoding()); // TE cannot be null
}
}

坑了四个小时。