在Java Http请求中,我们可以这样做以进行多部分HTTP POST。
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
FileBody bin = new FileBody(new File(fileName));
StringBody comment = new StringBody("Filename: " + fileName);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);
httppost.setEntity(reqEntity);
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
我如何使用WS.url或WS.WSRequest实现相同的目标?
WSRequestHolder wsReq = WS.url("http//url");
wsReq.setHeader("Content-type", "multipart/form-data");
答案 0 :(得分:5)
这很草率,绝对可以清理,但这就是我做的工作。随意把它做得更好。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import play.libs.WS;
import com.ning.http.multipart.FilePart;
import com.ning.http.multipart.MultipartRequestEntity;
import com.ning.http.multipart.Part;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// Build up the Multiparts
List<Part> parts = new ArrayList<>();
parts.add(new FilePart("file", new File(filename)));
Part[] partsA = parts.toArray(new Part[parts.size()]);
// Add it to the MultipartRequestEntity
MultipartRequestEntity reqE = new MultipartRequestEntity(partsA, null);
reqE.writeRequest(bos);
InputStream reqIS = new ByteArrayInputStream(bos.toByteArray());
WS.WSRequestHolder req = WS.url(InterchangeConfig.conflateUrl+"dataset")
.setContentType(reqE.getContentType());
req.post(reqIS).map(...);
// or req.post(reqIS).get();
这都是使用Play 2.0框架中已有的部分。
答案 1 :(得分:3)
现在唯一的解决方案是,不依赖于外部库,似乎是手动创建Multipart Form Data请求。这是一个使用play.libs.WS.url
:
WSRequestHolder wsRequestHolder = WS.url(URL);
String boundary = "--XYZ123--";
String body = "";
for (String key : data.keySet()) {
body += "--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\""
+ key + "\"\r\n\r\n"
+ data.get(key) + "\r\n";
}
body += "--" + boundary + "--";
wsRequestHolder.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
wsRequestHolder.setHeader("Content-length", String.valueOf(body.length()));
wsRequestHolder.post(body);
data
将是java.util.Map<String, String>
,其中包含您要作为表单参数传递的所有名称/值对。 randomString
是一个随机值,用于使请求与请求之间的边界更改。添加二进制数据将以相同的方式工作。
此http://www.htmlcodetutorial.com/forms/form_enctype.html是了解规格的好地方。
答案 2 :(得分:3)
使用上述方法进行游戏2.3的工作示例,同时在上传文件时添加了contentType。
public Promise<WSResponse> upload(Http.MultipartFormData.FilePart policyFilePart, String contentType) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
List<Part> parts = new ArrayList<>();
try {
parts.add(new FilePart("file", policyFilePart.getFile(), contentType, null));
parts.add(new StringPart("param1", "value1"));
parts.add(new StringPart("param2", "value2"));
Part[] partsA = parts.toArray(new Part[parts.size()]);
// Add it to the multipart request entity
MultipartRequestEntity requestEntity = new MultipartRequestEntity(partsA, new FluentCaseInsensitiveStringsMap());
requestEntity.writeRequest(bos);
InputStream reqIS = new ByteArrayInputStream(bos.toByteArray());
return WS.url(baseUrl + "upload")
.setContentType(requestEntity.getContentType())
.post(reqIS).map(new Function<WSResponse, WSResponse>() {
@Override
public WSResponse apply(WSResponse wsResponse) throws Throwable {
return wsResponse;
}
});
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
答案 3 :(得分:0)
根据播放API文档,似乎没有内置多部分POST主体。
但是,可以使用方法
创建自己的多部分主体post[T](body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]): Future[Response]
使用您选择的类型T,以及相应的Writeable和ContentTypeOf类型。
但这意味着要深入研究多部分机构如何使用HTTP。
答案 4 :(得分:0)
正如Romain Sertelon建议的那样,你可以编写一个Writeable来处理这种情况。这是我写的:
package utilities
import java.io.{ByteArrayOutputStream, File}
import com.ning.http.client.FluentCaseInsensitiveStringsMap
import com.ning.http.multipart.{MultipartRequestEntity, FilePart, StringPart}
import play.api.http.HeaderNames._
import play.api.http.{ContentTypeOf, Writeable}
import play.api.mvc.{Codec, MultipartFormData}
object MultipartFormDataWriteable {
implicit def contentTypeOf_MultipartFormData[A](implicit codec: Codec): ContentTypeOf[MultipartFormData[A]] = {
ContentTypeOf[MultipartFormData[A]](Some("multipart/form-data; boundary=__X_PROCESS_STREET_BOUNDARY__"))
}
implicit def writeableOf_MultipartFormData(implicit contentType: ContentTypeOf[MultipartFormData[File]]): Writeable[MultipartFormData[File]] = {
Writeable[MultipartFormData[File]]((formData: MultipartFormData[File]) => {
val stringParts = formData.dataParts flatMap {
case (key, values) => values map (new StringPart(key, _))
}
val fileParts = formData.files map { filePart =>
new FilePart(filePart.key, filePart.ref, filePart.contentType getOrElse "application/octet-stream", null)
}
val parts = stringParts ++ fileParts
val headers = new FluentCaseInsensitiveStringsMap().add(CONTENT_TYPE, contentType.mimeType.get)
val entity = new MultipartRequestEntity(parts.toArray, headers)
val outputStream = new ByteArrayOutputStream
entity.writeRequest(outputStream)
outputStream.toByteArray
})(contentType)
}
}
以下是如何使用它:
import utilities.MultipartFormDataWriteable._
...
val url = "https://example.com"
val dataParts = Map(
"foo" -> Seq("bar"),
"alice" -> Seq("bob")
)
val file = new jave.io.File(... path to a jpg ...)
val fileParts = Seq(new FilePart("attachment", "foo.jpg", Some("image/jpeg"), file)
val multipartFormData = MultipartFormData(dataParts, fileParts, Seq(), Seq())
WS.url(url).post(multipartFormData)
答案 5 :(得分:0)
接受的答案不适用于播放2.5。 play 2.6文档中的答案也不适用于2.5。
以下工作正常:
Http.MultipartFormData.FilePart part = new Http.MultipartFormData.FilePart("fileKey",
"abc.zip", "multipart/form-data",
FileIO.fromFile(new File("/home/testData/abc.zip")));
List<Http.MultipartFormData.Part<Source<ByteString, ?>>> data = Arrays.asList(part);
Http.RequestBuilder requestBuilder = AuthFakeRequest.getAuthFakeRequest(routes.MyController.uploadZip()).method(POST)
.bodyMultipart(data, mat);
Result result = route(app, requestBuilder);
对于mat
和app
对象,它们是在继承play.test.WithApplication
类时获得的。