- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 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/
我一直在使用 AJAX 从我正在创建的网络服务中解析 JSON 数组时遇到问题。我的前端是一个简单的 ajax 和 jquery 组合,用于显示从我正在创建的网络服务返回的结果。 尽管知道我的数据库查
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我在尝试运行 Android 应用程序时遇到问题并收到以下错误 java.lang.NoClassDefFoundError: com.parse.Parse 当我尝试运行该应用时。 最佳答案 在这
有什么办法可以防止etree在解析HTML内容时解析HTML实体吗? html = etree.HTML('&') html.find('.//body').text 这给了我 '&' 但我想
我有一个有点疯狂的例子,但对于那些 JavaScript 函数作用域专家来说,它看起来是一个很好的练习: (function (global) { // our module number one
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 8 年前。 Improve th
我需要编写一个脚本来获取链接并解析链接页面的 HTML 以提取标题和其他一些数据,例如可能是简短的描述,就像您链接到 Facebook 上的内容一样。 当用户向站点添加链接时将调用它,因此在客户端启动
在 VS Code 中本地开发时,包解析为 C:/Users//AppData/Local/Microsoft/TypeScript/3.5/node_modules/@types//index而不是
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我在将 json 从 php 解析为 javascript 时遇到问题 这是我的示例代码: //function MethodAjax = function (wsFile, param) {
我被赋予了将一种语言“翻译”成另一种语言的工作。对于使用正则表达式的简单逐行方法来说,源代码过于灵活(复杂)。我在哪里可以了解更多关于词法分析和解析器的信息? 最佳答案 如果你想对这个主题产生“情绪化
您好,我在解析此文本时遇到问题 { { { {[system1];1;1;0.612509325}; {[system2];1;
我正在为 adobe after effects 在 extendscript 中编写一些代码,最终变成了 javascript。 我有一个数组,我想只搜索单词“assemble”并返回整个 jc3_
我有这段代码: $(document).ready(function() { // }); 问题:FB_RequireFeatures block 外部的代码先于其内部的代码执行。因此 who
背景: netcore项目中有些服务是在通过中间件来通信的,比如orleans组件。它里面服务和客户端会指定网关和端口,我们只需要开放客户端给外界,服务端关闭端口。相当于去掉host,这样省掉了些
1.首先贴上我试验成功的代码 复制代码 代码如下: protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
什么是 XML? XML 指可扩展标记语言(eXtensible Markup Language),标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。 你可以通过本站学习 X
【PHP代码】 复制代码 代码如下: $stmt = mssql_init('P__Global_Test', $conn) or die("initialize sto
在SQL查询分析器执行以下代码就可以了。 复制代码代码如下: declare @t varchar(255),@c varchar(255) declare table_cursor curs
前言 最近练习了一些前端算法题,现在做个总结,以下题目都是个人写法,并不是标准答案,如有错误欢迎指出,有对某道题有新的想法的友友也可以在评论区发表想法,互相学习🤭 题目 题目一: 二维数组中的
我是一名优秀的程序员,十分优秀!