Retofit+Okhttp表单上传文件及参数处理大全
一、Retofit配置上传文件的方式
1. 仅参数上传
方式一
@FormUrlEncoded
@POST("upload")
Call<ResponseBody> uploadParams(@Field("username")String username,@Field("token")String token);
方式二
@FormUrlEncoded
@POST("upload")
Call<ResponseBody> uploadParams(@FieldMap Map<String,String> map);
方式三
@POST("upload")
Call<ResponseBody> uploadParams(@Body RequestBody body);
2. 文件上传
单文件上传
@Multipart
@POST("upload")
Call<ResponseBody> uploadOneFile(@Part MultipartBody.Part body);
调用方式:
File file = new File("");
RequestBody fileRQ = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
Call<ResponseBody> uploadCall = downloadService.uploadOneFile(part);
多文件上传
方式一
@Multipart
@POST("upload")
Call<ResponseBody> uploadFiles(@PartMap Map<String, RequestBody> map);
调用:
RequestBody fb = RequestBody.create(MediaType.parse("text/plain"), "hello,retrofit");
RequestBody fileTwo = RequestBody.create(MediaType.parse("image/*"), new File(Environment.getExternalStorageDirectory()
+ file.separator + "original.png"));
Map<String, RequestBody> map = new HashMap<>();
//这里的key必须这么写,否则服务端无法识别
map.put("file\"; filename=\""+ file.getName(), fileRQ);
map.put("file\"; filename=\""+ "2.png", fileTwo);
Call<ResponseBody> uploadCall = downloadService.uploadFiles(map);
方式二
@Multipart
@POST("upload")
Call<ResponseBody> uploadFiles(@Part List<MultipartBody.Part> parts);
调用:
RequestBody fileRQ = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
RequestBody fb = RequestBody.create(MediaType.parse("text/plain"), "hello,retrofit");
RequestBody fileTwo = RequestBody.create(MediaType.parse("image/*"), new File(Environment.getExternalStorageDirectory()
+ file.separator + "original.png"));
MultipartBody.Part two=MultipartBody.Part.createFormData("one","one.png",fileTwo);
List<MultipartBody.Part> parts=new ArrayList<>();
parts.add(part);
parts.add(two);
Call<ResponseBody> uploadCall = downloadService.uploadFiles(parts);
3. 文件+参数混合上传
方式一
@Multipart
@POST("upload")
Call<ResponseBody> uploadFile(@Part("body") RequestBody body, @Part MultipartBody.Part file);
调用:
MultipartBody.Part part = MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
RequestBody fb =RequestBody.create(MediaType.parse("text/plain"), "hello,retrofit");
Call<ResponseBody> uploadCall = downloadService.uploadFile(fb,part);
方式二
@POST("upload")
Call<ResponseBody> uploadFile(@Body RequestBody body);
调用:
File file = new File("path");
RequestBody fileRQ = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("picture", file.getName(), fileRQ);
RequestBody body=new MultipartBody.Builder()
.addFormDataPart("userName","lange")
.addFormDataPart("token","dxjdkdjkj9203kdckje0")
.addFormDataPart("header",file.getName(),fileRQ)
.build();
Call<ResponseBody> uploadCall = downloadService.uploadFile(body);
uploadCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.i("upload", response.isSuccessful() + "");
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
二、Okhttp拦截器添加
Retrofit配置
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
class RetrofitHelper private constructor() {
private var okHttpClient: OkHttpClient
private var retrofit: Retrofit
private val headerInterceptor: Interceptor
private val logInterceptor: HttpLoggingInterceptor
private object SingletonHolder {
val helper = RetrofitHelper()
}
companion object {
private var BASE_URL = ""
private const val DEFAULT_CONNECT_TIME = 10
private const val DEFAULT_WRITE_TIME = 15
private const val DEFAULT_READ_TIME = 15
const val TOKEN_KEY = "token"
const val UID_KEY = "uid"
const val LANGUAGE_KEY = "language"
const val COUNTRY_KEY = "country"
const val SUCCESS_CODE = 1
val context = Application.context
val instance = SingletonHolder.helper
}
init {
headerInterceptor = Interceptor {
val request = it.request().newBuilder()
.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
.addHeader("Connection", "keep-alive")
.addHeader("timestamp", (System.currentTimeMillis() / 1000).toString())
.build()
it.proceed(request)
}
SslUtils.initSslSocketFactorySingleByAll(context.applicationContext)
logInterceptor = HttpLoggingInterceptor()
logInterceptor.level = HttpLoggingInterceptor.Level.BODY
okHttpClient = OkHttpClient.Builder()
.connectTimeout(DEFAULT_CONNECT_TIME.toLong(), TimeUnit.SECONDS) //连接超时时间
.writeTimeout(DEFAULT_WRITE_TIME.toLong(), TimeUnit.SECONDS) //设置写操作超时时间
.readTimeout(DEFAULT_READ_TIME.toLong(), TimeUnit.SECONDS) //设置读操作超时时间
.addInterceptor(headerInterceptor)
.addInterceptor(LoggingInterceptor())
.sslSocketFactory(SslUtils.sSLSocketFactory,SslUtils.trustManager)
.build()
retrofit = Retrofit.Builder()
.client(okHttpClient) //设置使用okHttp网络请求
.baseUrl(BASE_URL) //设置服务器路径
.addConverterFactory(GsonConverterFactory.create()) //添加转化库,默认是Gson
.build()
}
fun <T> create(service: Class<T>?): T {
return retrofit.create(service)
}
}
日志拦截
import java.io.IOException;
import java.nio.charset.Charset;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
public class LoggingInterceptor implements Interceptor {
private static final String TAG = "LoggingInterceptor";
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Response response = chain.proceed(original);
LogUtil.e(TAG, String.format("...\n请求链接:%s\n请求方式:%s\n请求头:\n%s\n请求参数:\n%s\n响应码:%s\n请求响应:\n%s", original.url(),
original.method(), getRequestHeaders(original), getRequestInfo(original), response.code(), getResponseInfo(response)));
return response;
}
/**
* 打印请求头
*
* @param request 请求的对象
*/
private String getRequestHeaders(Request request) {
String str = "";
if (request == null) {
return str;
}
Headers headers = request.headers();
if (headers == null) {
return str;
}
return headers.toString();
}
/**
* 打印请求消息
*
* @param request 请求的对象
*/
private String getRequestInfo(Request request) {
String str = "";
if (request == null) {
return str;
}
RequestBody requestBody = request.body();
if (requestBody == null) {
return str;
}
if (requestBody instanceof MultipartBody) {
return "MultipartBody不显示";
}
try {
Buffer bufferedSink = new Buffer();
requestBody.writeTo(bufferedSink);
Charset charset = Charset.forName("utf-8");
str = bufferedSink.readString(charset);
} catch (Exception e) {
e.printStackTrace();
}
return str;
}
/**
* 打印返回消息
*
* @param response 返回的对象
*/
private String getResponseInfo(Response response) {
String str = "";
if (response == null || !response.isSuccessful()) {
return str;
}
ResponseBody responseBody = response.body();
long contentLength = responseBody.contentLength();
BufferedSource source = responseBody.source();
try {
source.request(Long.MAX_VALUE); // Buffer the entire body.
} catch (Exception e) {
e.printStackTrace();
}
Buffer buffer = source.buffer();
Charset charset = Charset.forName("utf-8");
if (contentLength != 0) {
str = buffer.clone().readString(charset);
}
return str;
}
}
发送+接收数据拦截
import android.content.Context;
import android.text.TextUtils;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.HashMap;
import java.util.Set;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
/**
* 处理拦截
*/
public class SafeInterceptor implements Interceptor {
private String TAG = "SafeInterceptor";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//指定域名不拦截
if (request.url().toString().endsWith("XXXX")) {
return chain.proceed(request);
}
HashMap<String, String> needSignMap = new HashMap<>();
//1.获取head数据
getRequestHeaders(request, needSignMap);
//2.获取queryMap数据
getQuery(request, needSignMap);
//3.获取mediaType:x-www-form-urlencoded,Body数据
//4.获取mediaType:multipart/form-data,value 类型和 file 类型。
getBody(request, needSignMap);
Request.Builder newBuilder = request.newBuilder();
newBuilder.addHeader("X-Unique-Sign", sign);
//6.body数据加密
RequestBody requestBody = request.body();
if (requestBody != null) {
if (requestBody instanceof FormBody) {
newBuilder.post(requestBody);
} else if (requestBody instanceof MultipartBody) {
newBuilder.post(requestBody);
} else {
String postBodyString = bodyToString(requestBody);
LogUtil.e(TAG, "请求参数:" + postBodyString);
if (!TextUtils.isEmpty(postBodyString)) {
String type = request.method();
if ("Post".equalsIgnoreCase(type)){
newBuilder.post(RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"), allBase));
}else if ("Put".equalsIgnoreCase(type)){
newBuilder.put(RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"), allBase));
}
}
}
}
//7.返回数据
request = newBuilder.build();
Response response = chain.proceed(request);
return getResponseString(response, sign, app_secret);
}
private void getBody(Request request, HashMap<String, String> needSignMap) {
RequestBody requestBody = request.body();
if (requestBody == null) return;
MediaType type = requestBody.contentType();
if (type != null) {
LogUtil.e(TAG, "接口请求Type:" + type);
if (requestBody instanceof FormBody) {
for (int i = 0; i < ((FormBody) requestBody).size(); i++) {
String name = ((FormBody) requestBody).encodedName(i);
if (!"file".equalsIgnoreCase(name)) {
needSignMap.put(name, ((FormBody) requestBody).encodedValue(i));
}
}
} else if (requestBody instanceof MultipartBody) {
MultipartBody body = (MultipartBody) requestBody;
HashMap<String, String> params = new HashMap<>();
HashMap<String, String> files = new HashMap<>();
for (MultipartBody.Part part : body.parts()) {
RequestBody body1 = part.body();
Headers headers = part.headers();
if (headers != null && headers.size() > 0) {
String[] split = headers.value(0).replace(" ", "").replace("\"", "").split(";");
if (split.length == 2) {
//文本
String[] keys = split[1].split("=");
try {
if (keys.length > 1 && body1.contentLength() < 1024) {
String key = keys[1];
String value = "";
Buffer buffer = new Buffer();
body1.writeTo(buffer);
value = buffer.readUtf8();
params.put(key, value);
}
} catch (IOException e) {
LogUtil.e(TAG,"getBody multipart:"+e.getMessage());
}
} else if (split.length == 3) {
//文件
String fileKey = "";
String fileName = "";
String[] keys = split[1].split("=");
String[] names = split[2].split("=");
if (keys.length > 1) fileKey = keys[1];
if (names.length > 1) fileName = names[1];
files.put(fileKey, fileName);
}
}
}
LogUtil.e(TAG,"文本参数:"+params);
params.remove("file");
LogUtil.e(TAG,"文件参数:"+files);
needSignMap.putAll(params);
} else {
if (type.toString().contains("x-www-form-urlencoded")) {
HashMap<String, String> urlencodedMap = new HashMap<>();
//buffer流
Buffer buffer = new Buffer();
try {
requestBody.writeTo(buffer);
String oldParamsJson = buffer.readUtf8();
Gson gson = new Gson();
urlencodedMap = gson.fromJson(oldParamsJson, HashMap.class); //原始参数
needSignMap.putAll(urlencodedMap);
} catch (IOException e) {
LogUtil.e(TAG,"getBody form:"+e.getMessage());
}
}
}
}
}
private void getQuery(Request request, HashMap<String, String> needSignMap) {
Set<String> paramterSet = request.url().queryParameterNames();
for (String itmeName : paramterSet) {
String itemValue = request.url().queryParameter(itmeName);
needSignMap.put(itmeName, itemValue);
}
}
private void getRequestHeaders(Request request, HashMap<String, String> signMap) {
if (request != null) {
Headers headers = request.headers();
if (headers != null) {
String timestampValue = headers.get("timestamp");
if (!TextUtils.isEmpty(timestampValue)) {
signMap.put("timestamp", timestampValue);
}
}
}
}
private String bodyToString(final RequestBody request) {
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if (copy != null){
copy.writeTo(buffer);
} else {
return "";
}
return buffer.readUtf8();
} catch (final IOException e) {
LogUtil.e(TAG, "bodyToString IOException");
return "";
}
}
/*处理响应*/
private Response getResponseString(Response response, String sign, String app_secret) throws UnsupportedEncodingException {
ResponseBody responseBody = response.body();
if (responseBody != null) {
long contentLength = responseBody.contentLength();
//判断返回内容中data加密
if (bodyEncoded(response.headers())) {
BufferedSource source = responseBody.source();
try {
source.request(Long.MAX_VALUE); // Buffer the entire body.
} catch (IOException e) {
LogUtil.e(TAG, "getResponseString IOException:"+ e.getMessage());
}
Buffer buffer = source.buffer();
Charset charset = Charset.forName("UTF-8");
MediaType contentType = responseBody.contentType();
if (contentType != null) {
try {
charset = contentType.charset(Charset.forName("UTF-8"));
} catch (UnsupportedCharsetException e) {
LogUtil.e(TAG, e.getMessage());
}
}
if (contentLength != 0) {
String res = buffer.clone().readString(charset);
// LogUtil.e(TAG, "响应数据:" + res);
BaseAResponse baseAsResponse = new Gson().fromJson(res, BaseAResponse.class);
String secretData = baseAesResponse.getData();
String result = secretData;
if (!TextUtils.isEmpty(secretData)) {
String contentEncoding = response.headers().get("Algorithm");
/* if (!TextUtils.isEmpty(result)){
BaseResponse response = new Gson().fromJson(result, BaseEcdhResponse.class);
}*/
} else {
result = res;
}
LogUtil.e(TAG, "解密数据:" + result);
MediaType mediaType = responseBody.contentType();
return response.newBuilder().body(ResponseBody.create(
mediaType,
result
)).build();
}
}
}
return response;
}
}
三、MultipartBody内部数据解析
直接上代码示例
kotlin
if (requestBody is MultipartBody) {
val params = mutableMapOf<String, String>()
val files = mutableMapOf<String, String>()
requestBody.parts().forEach {
val body = it.body()
it.headers()?.let {
val header = it.value(0)
val split = header.replace(" ", "").replace("\"", "").split(";")
when (split.size) {
2 -> {
//文本参数
val keys = split[1].split("=")
if (keys.size > 1 && body.contentLength() < 1024) {
val key = keys[1]
val buffer = Buffer()
body.writeTo(buffer)
val value = buffer.readUtf8()
params[key] = value
}
}
3 -> {
//文件
val fileKeys = split[1].split("=")
val fileKey = if (fileKeys.size > 1) {
fileKeys[1]
} else ""
val nameValue = split[2].split("=")
val fileName = if (nameValue.size > 1) nameValue[1] else ""
files[fileKey] = fileName
}
}
}
}
println("文件-->$files")
println("文本-->$params")
}
java
if (requestBody instanceof MultipartBody) {
MultipartBody body = (MultipartBody) requestBody;
Map<String, String> params = new HashMap<>();
Map<String, String> files = new HashMap<>();
for (MultipartBody.Part part : body.parts()) {
RequestBody body1 = part.body();
Headers headers = part.headers();
if (headers != null && headers.size() > 0) {
String[] split = headers.value(0).replace(" ", "").replace("\"", "").split(";");
if (split.length == 2) {
//文本
String[] keys = split[1].split("=");
if (keys.length > 1 && body1.contentLength() < 1024) {
String key = keys[1];
String value = "";
Buffer buffer = new Buffer();
body1.writeTo(buffer);
value = buffer.readUtf8();
params.put(key, value);
}
} else if (split.length == 3) {
//文件
String fileKey = "";
String fileName = "";
String[] keys = split[1].split("=");
String[] names = split[2].split("=");
if (keys.length > 1) fileKey = keys[1];
if (names.length > 1) fileName = names[1];
files.put(fileKey, fileName);
}
}
}
System.out.println("文本参数-->" + params);
System.out.println("文件参数-->" + files);
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/fepengwang/article/details/131110380