gpt4 book ai didi

android - 如何在 retrofit2 android 中解析来自多部分表单数据请求的响应

转载 作者:行者123 更新时间:2023-11-30 05:08:25 26 4
gpt4 key购买 nike

我正在使用 Retrofit 2 创建一个多部分表单数据请求,它工作正常并且服务器响应 200。我在解析响应时遇到问题。这是我的代码:

@POST("sync/mediaUpload")
@Multipart
Call<ResponseBody> uploadMediaFile(@Header("Authorization") String token,
@Part("userId") RequestBody userId,
@Part MultipartBody.Part file,
@Part("fileId") RequestBody photoId,
@Part("hash") RequestBody hash);


public Response<ResponseBody> uploadMediaFile(String token, String userId, File file, String fileName, String fileId, String hash) {

MediaService service = retrofit.create(MediaService.class);
MultipartBody.Part fileBody = prepareFilePart("file", file);
RequestBody userIdBody = RequestBody.create(MediaType.parse("text/plain"), userId);
RequestBody fileNameBody = RequestBody.create(MediaType.parse("text/plain"), fileName);
RequestBody fileIdBody = RequestBody.create(MediaType.parse("text/plain"), fileId);
RequestBody hashBody = RequestBody.create(MediaType.parse("text/plain"), hash);
Call<ResponseBody> call = service.uploadMediaFile(token, userIdBody, txIdBody, transIdBody, stepCodeBody,
fileBody, fileNameBody, fileIdBody, hashBody);
try {
return call.execute();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

@NonNull
private MultipartBody.Part prepareFilePart(String partName, File file) {
RequestBody requestFile = RequestBody.create(MediaType.parse("image/*"), file);
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}

当文件上传正确时,服务器返回一个Json对象。示例:

{
"fileName": "IMG_20190108_183751.jpg",
"fileId": "0",
"fileSizeInBytes": 216067
}

但是,在 call.execute() 中,改造返回:

--MultipartDataMediaFormatterBoundary1q2w3e
Content-Disposition: form-data; name="FileName"
IMG_20190108_183751.jpg

--MultipartDataMediaFormatterBoundary1q2w3e
Content-Disposition: form-data; name="FileId"
0

--MultipartDataMediaFormatterBoundary1q2w3e
Content-Disposition: form-data; name="FileSizeInBytes"
216067

我如何解析该响应?我尝试更改改造服务的签名以使用对象而不是 ResponseBody:

@POST("sync/mediaUpload")
@Multipart
Call<MediaUploadResponse> uploadMediaFile(@Header("Authorization") String token,
@Part("userId") RequestBody userId,
@Part MultipartBody.Part file,
@Part("fileId") RequestBody photoId,
@Part("hash") RequestBody hash);

还有我的对象

public class MediaUploadResponse {

public final String fileName;
public final String fileId;
public final long fileSizeInBytes;

public MediaUploadResponse(String fileName, String fileId, long
fileSizeInBytes) {
this.fileName = fileName;
this.fileId = fileId;
this.fileSizeInBytes = fileSizeInBytes;
}
}

但 Retrofit 抛出 MalformedJsonException

有没有人知道如何解决这个问题?

谢谢。

最佳答案

我给你的答案会用Gson streaming (流式传输速度)和 okhttp3 .请记住,当前显示的此代码未经测试。它是为了向您展示该做什么的想法。我从我当前正在运行的一个应用程序中获取它(这个想法已经实现并且正在运行)。这可能看起来有点矫枉过正。我有另一个问题,因为模糊点,请在下面发表评论。

1- 通过 retrofit 设置 GSON:

package whatever.package.you.want;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

public class DataService {
private static Retrofit retrofit = null;
private static final int CONNECTION_TIMEOUT = 45;//s
private static final int READ_TIMEOUT = 45;//s
private static final int WRITE_TIMEOUT = 45;//s
private static final String MEDIA_TYPE = "application/json";//"multipart/form-data"; //"text/plain";
private static final DATA_SERVICE_BASE_URL = "https://stackoverflow.com"; // your desired URL
//I suppose you have your custom declarations here

public static Retrofit getClient(String yourURL) {

Gson gson = new GsonBuilder()
.setLenient()
.setPrettyPrinting()
.create();

//https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor
/*HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);*/

final OkHttpClient client = new OkHttpClient.Builder()
/*.addInterceptor(logging)*/
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.build();

if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(yourURL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson)) //https://github.com/square/retrofit/tree/master/retrofit-converters/gson
.addConverterFactory(ScalarsConverterFactory.create()) //https://github.com/square/retrofit/tree/master/retrofit-converters/scalars
.build();
}
return retrofit;
}

public static DataService getUserDataService() {
return getClient(DATA_SERVICE_BASE_URL).create(UserDataServiceInterface.class);
}
}

2- 您的模型 MediaUploadResponse.class :

package whatever.package.you.want;

import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;


@JsonAdapter(MediaUploadResponseAdapter.class)
public class MediaUploadResponse {

@SerializedName("fileName")
private String fileName = "";

@SerializedName("fileId")
private String fileID = "";

@SerializedName("fileSizeInBytes")
private long fileSizeInBytes = "";


public String getFileName() {
return fileName;
}

public void setFileName(String fileName) {
this.fileName = fileName;
}

public String getFileId() {
return fileId;
}

public void setFileId(String fileId) {
this.fileId = fileId;
}

public String getFileSizeInBytes() {
return fileSizeInBytes;
}

public void setFileSizeInBytes(long fileSizeInBytes) {
this.fileSizeInBytes = fileSizeInBytes;
}
}

3- 模型的适配器 MediaUploadResponseAdapter.class,用于序列化和反序列化:

package whatever.package.you.want;

import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import whatever.MediaUploadResponse;
import whatever.JsonAdapterUtils;

import java.io.IOException;


public class MediaUploadResponseAdapter extends BaseJsonAdapter<MediaUploadResponse> {

@Override
public MediaUploadResponse read(JsonReader reader) throws IOException {
MediaUploadResponse element = new MediaUploadResponse();
String fieldName = null;

if(reader.peek() == JsonToken.NULL){
reader.nextNull();
return null;
}

reader.beginObject();
while (reader.hasNext()) {
JsonToken token = reader.peek();
if(token.equals(JsonToken.NAME))
fieldName = reader.nextName();

if (fieldName.equals("fileName") && token != JsonToken.NULL)
element.setFileName(JsonAdapterUtils.stringFromJsonReader(reader));

else if (fieldName.equals("fileId") && token != JsonToken.NULL)
element.setFileID(JsonAdapterUtils.stringFromJsonReader(reader));

else if (fieldName.equals("fileSizeInBytes") && token != JsonToken.NULL)
element.SetFileSizeInBytes(JsonAdapterUtils.longFromJsonReader(reader));

else
reader.skipValue();
}
reader.endObject();

return element;
}

@Override
public void write(JsonWriter writer, MediaUploadResponse element) throws IOException {
if(element == null){
writer.nullValue();
return;
}
writer.beginObject();
writer.name("fileName").value(element.getFileName());
writer.name("fileId").value(element.getFileId());
writer.name("fileSizeInBytes").value(element.getFileSizeInBytes());
writer.endObject();
}
}

4- 使用此调用(您发布的第二个调用)(编辑:这是主要问题的答案):

@Headers({
"Accept: application/json"
})
@POST("sync/mediaUpload")
@Multipart
Call<MediaUploadResponse> uploadMediaFile(@Header("Authorization") String token,
@Part("userId") RequestBody userId,
@Part MultipartBody.Part file,
@Part("fileId") RequestBody photoId,
@Part("hash") RequestBody hash);

5- 一些奖励,这样你就不会错过一些依赖项:

a- BaseJsonAdapter.class 类(将有助于解析列表):

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

/**
* Created by mamboa on 3/6/2018.
*/

public class BaseJsonAdapter<T> extends TypeAdapter<T>{

public ArrayList<T> readArray(JsonReader reader) throws IOException {
if(reader.peek() == JsonToken.NULL){
reader.nextNull();
return null;
}

ArrayList<T> elements = new ArrayList<T>();

reader.beginArray();
while (reader.hasNext()) {
T value = read(reader);
if(value != null)
elements.add(value);
else {
break;
}
}
reader.endArray();
return elements;
}

public void writeArray(JsonWriter writer, List<T> messages) throws IOException {
writer.beginArray();
for (T message : messages) {
write(writer, message);
}
writer.endArray();
}

public T read(JsonReader reader) throws IOException {
return null;
}

public void write(JsonWriter writer, T t) throws IOException {
}
}

b- 最后是 JsonAdapterUtils:

package whatever.Utils;


import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

import java.io.IOException;

/**
* Created by mamboa on 3/7/2018.
*/

public class JsonAdapterUtils {

public static final int INTEGER_DEFAULT = -1;
public static final String STRING_DEFAULT = "";
public static final boolean BOOLEAN_DEFAULT = false;

public static int intFromJsonReader(JsonReader reader) throws IOException{
try {
if(reader.peek() == JsonToken.BOOLEAN)
return fromBooleanToInt(reader.nextBoolean());

String resultValue = reader.nextString();
if("".equals(resultValue))
return INTEGER_DEFAULT;

return Integer.parseInt(resultValue);
}
catch (IOException ex){
return returnDefaultAfterException(reader);
}
catch (IllegalStateException ex){
return returnDefaultAfterException(reader);
}
catch (NumberFormatException ex){
return returnDefaultAfterException(reader);
}
}

public static long longFromJsonReader(JsonReader reader) throws IOException{
try {
if(reader.peek() == JsonToken.BOOLEAN)
return fromBooleanToInt(reader.nextBoolean());

String resultValue = reader.nextString();
if("".equals(resultValue))
return INTEGER_DEFAULT;

return Long.parseLong(resultValue);
}
catch (IOException ex){
return returnDefaultAfterException(reader);
}
catch (IllegalStateException ex){
return returnDefaultAfterException(reader);
}
catch (NumberFormatException ex){
return returnDefaultAfterException(reader);
}
}

public static float floatFromJsonReader(JsonReader reader) throws IOException{
try {
if(reader.peek() == JsonToken.BOOLEAN)
return fromBooleanToInt(reader.nextBoolean());

String resultValue = reader.nextString();
if("".equals(resultValue))
return INTEGER_DEFAULT;

return Float.parseFloat(resultValue);
}
catch (IOException ex){
return returnDefaultAfterException(reader);
}
catch (IllegalStateException ex){
return returnDefaultAfterException(reader);
}
catch (NumberFormatException ex){
return returnDefaultAfterException(reader);
}
}

public static double doubleFromJsonReader(JsonReader reader) throws IOException{
try {
if(reader.peek() == JsonToken.BOOLEAN)
return fromBooleanToInt(reader.nextBoolean());

String resultValue = reader.nextString();
if("".equals(resultValue))
return INTEGER_DEFAULT;

return Double.parseDouble(resultValue);
}
catch (IOException ex){
return returnDefaultAfterException(reader);
}
catch (IllegalStateException ex){
return returnDefaultAfterException(reader);
}
catch (NumberFormatException ex){
return returnDefaultAfterException(reader);
}
}

public static String stringFromJsonReader(JsonReader reader) throws IOException{
String resultValue = "";
try {
if(reader.peek() == JsonToken.BOOLEAN)
return boolFromJsonReader(reader)? "true" : "false";

resultValue = reader.nextString();
return !resultValue.equals("") ? resultValue : STRING_DEFAULT;
}
catch (IOException ex){
reader.skipValue();
return STRING_DEFAULT;
}
catch (IllegalStateException ex){
reader.skipValue();
return STRING_DEFAULT;
}
}

public static boolean boolFromJsonReader(JsonReader reader)throws IOException{
try {
if(reader.peek() == JsonToken.BOOLEAN)
return reader.peek() == JsonToken.BOOLEAN ? reader.nextBoolean() : BOOLEAN_DEFAULT;
}
catch (IOException ex){
reader.skipValue();
}
return BOOLEAN_DEFAULT;
}

private static int returnDefaultAfterException(JsonReader reader) throws IOException {
if(reader != null) reader.skipValue();
return INTEGER_DEFAULT;
}

private static int fromBooleanToInt(boolean value){
return value ? 1 : 0;
}

public static String serializeObject(Object object){
if(object != null) {
Gson gson = new Gson();
return gson.toJson(object);
}
return "";
}
}

编辑:问题:

问题是在 http 请求的参数中,服务器必须知道调用者想要 JSON 格式的响应。所以解决方案Retrofit 2 ,当使用Multipart时就是添加如下(在请求之上):

@Headers({
"Accept: application/json"
})

关于android - 如何在 retrofit2 android 中解析来自多部分表单数据请求的响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54133578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com