4

我正在尝试借助 Google HTTP 客户端库 v1.14.1 在 Box API 中调用此特定方法http://developers.box.com/docs/#files-upload-a-file 。目前我认为没有办法做到这一点。

如果我使用http://hc.apache.org/httpclient-3.x/methods/multipartpost.html,我将添加 2 项 StringPart 和 1 项 FilePart。

在 Google HTTP 客户端库中,我只看到 MultipartContent 和 Part 类似乎无法处理纯名称/值对,如上面引用的 StringPart。

以下是 Apache HTTP 客户端示例的摘录:

HttpPost httppost = new HttpPost("http://localhost:8080" +
                "/servlets-examples/servlet/RequestInfoExample");

FileBody bin = new FileBody(new File(args[0]));
StringBody comment = new StringBody("A binary file of some kind");

MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);

httppost.setEntity(reqEntity);

我想完成类似的事情,但使用 Google HTTP Client。欢迎大家提出意见!

4

2 回答 2

6

经过一番调查,我发现我需要 Box API 的 Content-Type: multipart/form-data 并适当地构建请求。我使用的 Google HTTP 客户端版本不可能,所以我自己实现了 MultipartFormDataContent 类,它非常适合库。这是该课程的完整列表。也许它可以包含在库中。

/*
 * Copyright (c) 2013 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
/**
 * This is a modification of com.google.api.client.http.MultipartContent from
 * Google HTTP Client library to support multipart/form-data requests.
 *
 * The original author is Yaniv Inbar.
 */
public class MultipartFormDataContent extends AbstractHttpContent {
    private static final String NEWLINE = "\r\n";
    private static final String TWO_DASHES = "--";
    private ArrayList<Part> parts = new ArrayList<Part>();

    public MultipartFormDataContent() {
        super(new HttpMediaType("multipart/form-data").setParameter("boundary", "__END_OF_PART__"));
    }

    @Override
    public void writeTo(OutputStream out) throws IOException {
        Writer writer = new OutputStreamWriter(out, getCharset());
        String boundary = getBoundary();
        for (Part part : parts) {
            HttpHeaders headers = new HttpHeaders().setAcceptEncoding(null);
            if (part.headers != null) {
                headers.fromHttpHeaders(part.headers);
            }
            headers.setContentEncoding(null)
                   .setUserAgent(null)
                   .setContentType(null)
                   .setContentLength(null);
            // analyze the content
            HttpContent content = part.content;
            StreamingContent streamingContent = null;
            String contentDisposition = String.format("form-data; name=\"%s\"", part.name);
            if (part.filename != null) {
                headers.setContentType(content.getType());
                contentDisposition += String.format("; filename=\"%s\"", part.filename);
            }
            headers.set("Content-Disposition", contentDisposition);
            HttpEncoding encoding = part.encoding;
            if (encoding == null) {
                streamingContent = content;
            } else {
                headers.setContentEncoding(encoding.getName());
                streamingContent = new HttpEncodingStreamingContent(content, encoding);
            }
            // write separator
            writer.write(TWO_DASHES);
            writer.write(boundary);
            writer.write(NEWLINE);
            // write headers
            HttpHeaders.serializeHeadersForMultipartRequests(headers, null, null, writer);
            // write content
            if (streamingContent != null) {
                writer.write(NEWLINE);
                writer.flush();
                streamingContent.writeTo(out);
                writer.write(NEWLINE);
            }
        }
        // write end separator
        writer.write(TWO_DASHES);
        writer.write(boundary);
        writer.write(TWO_DASHES);
        writer.write(NEWLINE);
        writer.flush();
    }

    @Override
    public boolean retrySupported() {
        for (Part part : parts) {
            if (!part.content.retrySupported()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public MultipartFormDataContent setMediaType(HttpMediaType mediaType) {
        super.setMediaType(mediaType);
        return this;
    }

    /**
     * Adds an HTTP multipart part.
     *
     * <p>
     * Overriding is only supported for the purpose of calling the super
     * implementation and changing the return type, but nothing else.
     * </p>
     */
    public MultipartFormDataContent addPart(Part part) {
        parts.add(Preconditions.checkNotNull(part));
        return this;
    }

    /**
     * Sets the boundary string to use.
     *
     * <p>
     * Defaults to {@code "END_OF_PART"}.
     * </p>
     *
     * <p>
     * Overriding is only supported for the purpose of calling the super
     * implementation and changing the return type, but nothing else.
     * </p>
     */
    public MultipartFormDataContent setBoundary(String boundary) {
        getMediaType().setParameter("boundary", Preconditions.checkNotNull(boundary));
        return this;
    }

    /**
     * Single part of a multi-part request.
     *
     * <p>
     * Implementation is not thread-safe.
     * </p>
     */
    public static final class Part {
        private String name;
        private String filename;
        private HttpContent content;
        private HttpHeaders headers;
        private HttpEncoding encoding;

        public Part setContent(HttpContent content) {
            this.content = content;
            return this;
        }

        public Part setHeaders(HttpHeaders headers) {
            this.headers = headers;
            return this;
        }

        public Part setEncoding(HttpEncoding encoding) {
            this.encoding = encoding;
            return this;
        }

        public Part setName(String name) {
            this.name = name;
            return this;
        }

        public Part setFilename(String filename) {
            this.filename = filename;
            return this;
        }
    }
}
于 2013-04-14T14:54:23.130 回答
2

几个月来,我一直在为 google-http-java-client 中的这个小限制而苦苦挣扎,不久前我想出了一个旧的 MultipartRelatedContent 类的丑陋和冗余版本。现在我将 Google 库更新到最新的 1.15.0-rc 并且我发现将 MultipartContent 子类化并制作适合任何类型的“multipart/form-data”内容的体面的东西非常容易。

目前你可以在这里找到它: https ://github.com/marcosalis/kraken/blob/master/kraken_lib/src/main/java/com/google/api/client/http/MultipartFormDataContent.java

一个简短的使用示例:

File file = new File("/path/image.jpg");
FileContent fileContent = new FileContent("application/octet-stream", file);
MultipartFormDataContent multipart = new MultipartFormDataContent();
multipart.addPart(new Part(fileContent), "image", file.getName());
request.setContent(multipart); // sets the content to the request

“image”将是“content-disposition”标头中“name”键的值,文件名(在本例中为 image.jpg)将是“filename”键的(可选)值。

以同样的方式,您可以根据需要添加任意数量的不同部分(也可以嵌套其他“多部分/混合”内容,只需确保使用不同的边界字符串)到第一级多部分内容。

于 2013-06-17T15:29:43.160 回答