Java 在Android中发送mulipart/form数据请求

Java 在Android中发送mulipart/form数据请求,java,android,rest,jersey,multipartform-data,Java,Android,Rest,Jersey,Multipartform Data,我目前正在创建一个Android应用程序,但遇到了一个问题。 我用Java和Jersey创建了后端部分(托管在服务器上) 我的所有web服务都是POST并返回JSON字符串,几乎所有这些服务都只需要字符串,但其中一些服务还需要接收文件 当我用Google Postman调用web服务时,一切都正常 当我将来自Android项目的POST请求发送到我(为另一个项目)创建的php文件时,它也可以正常工作 但当我尝试向我的web服务发送请求时,启动Android应用程序时会出错。根据内容类型,响应

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

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

  • 当我用Google Postman调用web服务时,一切都正常
  • 当我将来自Android项目的POST请求发送到我(为另一个项目)创建的php文件时,它也可以正常工作
但当我尝试向我的web服务发送请求时,启动Android应用程序时会出错。根据内容类型,响应代码为415或500

我的问题是,我应该如何设置两侧的内容类型,以便从Android向我的服务器发送post请求并获取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");

提前感谢。

尝试将两侧的
内容类型设置为
application/json
。也就是说,如果要向服务器发送JSON字符串。如果要发送的文件是文本文件,请使用
application/text
。否则,请查找有关不同文件格式的正确
内容类型的信息。

如果您不知道自己在做什么,尝试格式化多部分请求并不是一项简单的任务。您可以查看示例格式和一些说明的详细信息

   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--
当您发出请求时,主体(和内容类型头)应该是这样的。我制作了简单的助手类,它适用于简单的字符串和文件案例。我没花太长时间就完成了,而且我还没有进行过战斗测试,但它适用于简单的用例。就个人而言,我可能会做一些重构,但这会给你一个起点

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;
        }
    }
}
但就我个人而言,我会选择一个已经具备此功能的库。例如,它具有多部分支持。它是一个非常流行的rest客户端库。这里有一个例子

您首先需要依赖关系

马文

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

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);

感谢您的回答,但是,我对服务器进行了编程,以便我期望作为输入的值是一个键和值列表。与GET请求中完全相同,在GET请求中添加(键、值)对。我的问题是如何将这种类型的数据发送到Java服务器
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);