在Android中发送mulipart / form-data请求

时间:2015-08-21 19:29:34

标签: java android rest jersey multipartform-data

我目前正在创建Android应用,但我遇到了一个问题。 我用Java和Jersey创建了后端部分(托管在服务器上)。

我的所有Web服务都是POST并返回一个JSON字符串,几乎所有这些字符串都只需要字符串,但其中一些还需要接收文件。

  • 当我使用Google Postman调用网络服务时,一切正常。
  • 当我从我的Android项目发送POST请求到我创建的php文件(对于另一个项目)时,它也可以正常工作。

但是当我尝试向我的网络服务发送请求时,我在启动Android应用时遇到错误。响应代码为415或500,具体取决于内容类型。

我的问题是,如何在两侧设置内容类型,以便将发布请求从Android发送到我的服务器并获取JSON字符串?我需要添加,我有时也需要发送文件通过POST请求。

这就是我在Java代码中的内容

@POST
@Path("/login")
@Consumes("multipart/form-data")

public String getLogin(@FormDataParam("mail") String mail,
        @FormDataParam("pwd") String pwd){ ...

这就是我的Android代码中的内容

HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod(p.getMethod());
con.setRequestProperty("Content-type", "multipart/form-data");

提前谢谢。

2 个答案:

答案 0 :(得分:0)

尝试将Content-Type设置为application/json。也就是说,如果您要向服务器发送JSON字符串。如果您要发送的文件是文本文件,请使用application/text。否则,请查看here以获取有关不同文件格式的正确Content-Type的信息。

答案 1 :(得分:0)

如果您不知道自己在做什么,尝试格式化多部分请求并非易事。你可以看到W3C documentation的样本格式和一些解释

   Content-Type: multipart/form-data; boundary=AaB03x

   --AaB03x
   Content-Disposition: form-data; name="submit-name"

   Larry
   --AaB03x
   Content-Disposition: form-data; name="files"; filename="file1.txt"
   Content-Type: text/plain

   ... contents of file1.txt ...
   --AaB03x--

在发出请求时,这几乎就是正文(和Content-Type标题)的样子。我已经制作了简单的帮助器类,适用于简单的String和文件盒。它并没有花太长时间制作,我没有经过测试,但它适用于简单的用例。我个人可能会做一些重构,但它会给你一个起点。

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.List;

public class MultipartHelper {

    public String contentType;
    public String boundary;
    public HttpURLConnection connection;

    private final List<FilePart> fileParts = new ArrayList<>();
    private final List<StringPart> stringParts = new ArrayList<>();

    public MultipartHelper(HttpURLConnection connection) throws IOException {
        this(connection, "multipart/form-data");
    }

    public MultipartHelper(HttpURLConnection connection, String contentType) throws IOException {
        this.boundary = String.valueOf(System.currentTimeMillis());
        this.connection = connection;
        contentType = contentType == null? "multipart/form-data": contentType;
        contentType += "; boundary=" + boundary;

        connection.setRequestProperty("Content-Type", contentType);
    }

    public void addStringPart(String data, String name) {
        stringParts.add(new StringPart(data, name));
    }

    public void addFilePart(File file, String contentType, String name) {
        if (contentType == null) {
            contentType = "application/octet-stream";
        }
        fileParts.add(new FilePart(file, contentType, name));
    }

    public void makeRequest() {
        Writer writer = null;
        try {
            OutputStream out = connection.getOutputStream();
            writer = new BufferedWriter(new OutputStreamWriter(out));

            for (StringPart sp: stringParts) {
                writer.write("--" + boundary + "\r\n");
                writer.write("Content-Disposition: form-data; name=" + sp.name + "\r\n");
                writer.write("Content-Type: text/plain\r\n\r\n");
                writer.write(sp.data + "\r\n");
            }
            writer.flush();

            InputStream in = null;
            for (FilePart fp: fileParts) {
                writer.write("--" + boundary + "\r\n");
                writer.write("Content-Disposition: form-data; name=" 
                        + fp.name + "; filename=" + fp.file.getName() + "\r\n");
                writer.write("Content-Type: " + fp.contentType + "\r\n\r\n");
                writer.flush();

                in = new FileInputStream(fp.file);
                int count;
                byte[] buffer = new byte[2048];
                while ((count = in.read(buffer)) != -1) {
                    out.write(buffer, 0, count);
                }
                out.flush();
                writer.write("\r\n");
                writer.flush();

                in.close();
            }
            writer.write("--" + boundary + "--\r\r");
            writer.flush();
            out.close();
            writer.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    class StringPart {
        String data;
        String name;
        public StringPart(String data, String name) {
            this.data = data;
            this.name = name;
        }
    }

    class FilePart {
        File file;
        String name;
        String contentType;
        public FilePart(File file, String contentType, String name) {
            this.file = file;
            this.name = name;
            this.contentType = contentType;
        }
    }
}

使用示例

final String urlStr = "http://localhost:8080/api/upload";
URL url = new URL(urlStr);
HttpURLConnection connection = (HttpURLConnection)url.openConnection(
        new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 8888)));
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");

MultipartHelper multipart = new MultipartHelper(connection);
multipart.addStringPart("Hello Part 1", "string1");
multipart.addFilePart(new File("stackoverflow.png"), "image/png", "image");

multipart.makeRequest();

我个人虽然,我会选择已经拥有此功能的图书馆。例如,Retrofit具有多部分支持。这是一个非常受欢迎的休息客户端库。这是一个例子

首先需要依赖

的Maven

<dependency>
    <groupId>com.squareup.retrofit</groupId>
    <artifactId>retrofit</artifactId>
    <version>1.9.0</version>
</dependency>

摇篮

compile 'com.squareup.retrofit:retrofit:1.9.0'

首先,您需要一个客户端服务接口

import retrofit.http.Multipart;
import retrofit.http.POST;
import retrofit.http.Part;
import retrofit.mime.TypedFile;
import retrofit.mime.TypedString;

public interface UploadService {

    @Multipart
    @POST("/upload")
    retrofit.client.Response upload(@Part("image") TypedFile image, 
                                    @Part("string1") TypedString string1);
}

然后发出请求

RestAdapter adapter = new RestAdapter.Builder()
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .setEndpoint("http://localhost:8080/api")
        .build();

UploadService service = adapter.create(UploadService.class);
TypedFile file = new TypedFile("image/png", new File("stackoverflow.png"));
TypedString str = new TypedString("Hello World");

retrofit.client.Response response = service.upload(file, str);