【问题标题】:HTTP POST multipart/form-data upload file using Java on the Asana API [closed]在 Asana API 上使用 Java 的 HTTP POST 多部分/表单数据上传文件 [关闭]
【发布时间】:2015-04-28 00:10:48
【问题描述】:

如何使用纯java.net来attach a file to a task using the Asana API

具体来说,我如何向 Asana API 发出格式良好的 HTTP POST multipart/form-data 编码请求,以便成功地将文件附加到任务?

【问题讨论】:

    标签: java multipartform-data asana


    【解决方案1】:

    Asana API 期望附件通过带有多部分/表单数据编码文件的 HTTP POST 请求上传到任务:

    https://asana.com/developers/api-reference/attachments#upload

    正如this answer 中解释的关于换行符的 HTTP 规范,请确保您使用的是\r\n 换行符,因为 Java 会将大多数 println() 方法转换为依赖于平台的 line.separator 并且 Asana 服务器可能无法容忍格式不正确的换行符。

    格式良好的 multipart/form-data POST 请求将如下所示:

    Authorization: Basic <BASE64_ENCODED_AUTH>
    Content-Type: multipart/form-data; boundary=14d07d7cbcf
    User-Agent: Java/1.7.0_76
    Host: localhost:8080
    Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    Connection: keep-alive
    Content-Length: 141
    
    --14d07d7cbcf
    Content-Disposition: form-data; name="file"; filename="example.txt"
    Content-Type: text/plain
    
    A file
    
    --14d07d7cbcf--
    

    这是一个 Java 实现,它纯粹使用 java.net 类为 Asana 附件 API 手动构建格式良好的 multipart/form-data 编码的 POST 请求:

    import org.apache.commons.codec.binary.Base64;
    
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class AttachFileToTask {
        // Use HTTP compliant line feeds in the request.
        // Note that Java println() methods may use platform dependent line feeds.
        private static String LINE_FEED = "\r\n";
    
        public static void main(String[] args) throws Exception {
            // Task attachments endpoint
            String url = "https://app.asana.com/api/1.0/tasks/<TASK_ID>/attachments";
            File theFile = new File("/path/to/file.txt");
    
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
    
            // Set basic auth header
            String apiKey = "<API_KEY>" + ":";
            String basicAuth = "Basic " + new String(new Base64().encode(apiKey.getBytes()));
            connection.setRequestProperty("Authorization", basicAuth);
    
            // Indicate a POST request
            connection.setDoOutput(true);
    
            // A unique boundary to use for the multipart/form-data
            String boundary = Long.toHexString(System.currentTimeMillis());
    
            // Construct the body of the request
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
    
            PrintWriter writer = null;
            try {
                writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
    
                String fileName = theFile.getName();
                writer.append("--" + boundary).append(LINE_FEED);
                writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"").append(LINE_FEED);
                writer.append("Content-Type: text/plain").append(LINE_FEED);
                writer.append(LINE_FEED);
    
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new InputStreamReader(new FileInputStream(theFile), "UTF-8"));
                    for (String line; (line = reader.readLine()) != null; ) {
                        writer.append(line).append(LINE_FEED);
                    }
                } finally {
                    if (reader != null) try {
                        reader.close();
                    } catch (IOException logOrIgnore) {
                    }
                }
    
                writer.append(LINE_FEED);
                writer.append("--" + boundary + "--").append(LINE_FEED);
                writer.append(LINE_FEED);
                writer.flush();
                writer.close();
            } catch (Exception e) {
                System.out.append("Exception writing file" + e);
            } finally {
                if (writer != null) writer.close();
            }
    
            System.out.println(connection.getResponseCode()); // Should be 200
            System.out.println(connection.getResponseMessage());
        }
    }
    

    请注意,在个人使用或实用程序脚本开发之外,不鼓励使用 API 密钥进行基本身份验证。为多个用户部署生产应用程序时,请使用 Asana Connect (OAuth 2.0)

    【讨论】:

    • 这个答案很好,只是需要一些修改,因为有一个错误。在读取要上传的文件之前,您需要制作 writer.flush()。将文件写入流后,写入 LINE_FEED,之后需要再次 make writer.flush() 才能将最后一个边界写入流。
    • 我不相信这些 writer.flush() 调用是必要的。我生成了一个相当大的文件并将其上传到具有上述代码的任务中,并且没有发现任何问题。您可以尝试通过以下方式生成文件:dd if=/dev/random of=/tmp/example.txt count=1024 bs=1024 &amp;&amp; echo "END OF FILE" &gt;&gt; /tmp/example.txt 上传并检查任务附件中的“END OF FILE”。
    猜你喜欢
    • 2017-07-18
    • 2016-06-29
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多