8

在 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");
4

6 回答 6

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 框架中的部分。

于 2013-09-10T15:41:33.603 回答
3

目前唯一不依赖外部库的解决方案似乎是手动创建多部分表单数据请求。这是一个如何完成的示例,使用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是了解规范的好地方。

于 2014-05-27T16:49:42.890 回答
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;
    }
}
于 2017-04-05T10:39:29.163 回答
0

根据 play API 文档,似乎没有内置的多部分 POST 正文。

但是,可以使用该方法创建自己的多部分主体

post[T](body: T)(implicit wrt: Writeable[T], ct: ContentTypeOf[T]): Future[Response]

使用您选择的类型 T,以及相应的 Writeable 和 ContentTypeOf 类型。

但这意味着要深入研究多部分主体如何与 HTTP 一起工作。

于 2013-02-13T10:17:48.030 回答
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)
于 2015-06-24T05:11:53.470 回答
0

接受的答案不适用于 play 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);

Formatapp对象,它们是在继承play.test.WithApplication类时获得的。

于 2019-01-09T13:49:41.843 回答