美文网首页
Retrofit 上传图片的坑

Retrofit 上传图片的坑

作者: 寒涵 | 来源:发表于2018-09-12 11:09 被阅读407次

    TIP 不是原创,只是记录一下 ,侵删!

    内容

    一、使用Retrofit上传文件时遇到的坑。项目中注册接口中有上传头像的功能,本以为上传头像是一个很简单的事情,可万万没想到使用Retrofit上传头像时却遇到了一个大坑。填这个坑花费了足足两天的时间。

    先来看下上传文件时遇到的异常信息:

    java.lang.IllegalArgumentException: Invalid % sequence at 432: --8c46470b-77e7-4dd8-b4e5-55f6968db182
    
    Content-Disposition: form-data; name="phone"
    
    Content-Length: 111551526--8c46470b-77e7-4dd8-b4e5-55f6968db182
    
    Content-Disposition: form-data; name="password"
    
    Content-Length: 6123123--8c46470b-77e7-4dd8-b4e5-55f6968db182
    
    Content-Disposition: form-data; name="uploadFile"; filename="test.txt"
    
    Content-Type: multipart/form-dataContent-Length: 27
    
    Hello World %--8c46470b-77e7-4dd8-b4e5-55f6968db182--
    

    分析上面的日志可以知道,错误的原因是因为文件中存在非法的参数“%”。什么情况啊,难道上传文件还不能包含“%”了这不科学啊。况且试验了图片上传每张图片流中都包含%。也就是所有图片上传均失败。于是自己又写了一个test.txt 
    

    的文件放到了手机里边测试,当test.txt文件中写入Hello World时候测试上传没有

    异常,但当我在Hello World末尾加了%后就出现了java.lang.IllegalArgumentException: Invalid % sequence at 432

    这个异常!刚开始的时候以为是自己上传文件部分代码写的有问题。于是参考网上的代码试了各种上传方法均无济于事。接着开始百度看网上是否有类似问题,但是几乎搜遍了整个百度也没有找到问题的解决方案。后来转战谷歌,强大的谷歌上也没有找到解决办法!无奈之下只好自己调了,于是开始逐一排查自己封装的代码是否有问题。经过不懈的努力终于找到了问题所在。
    请看下面代码

    public class RetrofitUtils {
    
        private static final long DEFAULT_TIMEOUT = 10;
    
        private volatile static RetrofitUtils apiEngine;
        private Retrofit retrofit;
    
        private RetrofitUtils() {
    
            //日志拦截器
            HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor((String message) -> {
    
                try {
                    String text = URLDecoder.decode(message, "utf-8");
                    Log.e("OKHttp-----", text);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    Log.e("OKHttp-----", message);
                }
            });
            loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
    
            //缓存
            int size = 1024 * 1024 * 100;
            File cacheFile = new File(App.getContext().getCacheDir(), "OkHttpCache");
            Cache cache = new Cache(cacheFile, size);
    
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                    .addNetworkInterceptor(new NetworkInterceptor())
                    .addInterceptor(loggingInterceptor)
                    .cache(cache)
                    .build();
    
            retrofit = new Retrofit.Builder()
                    .baseUrl(Contact.BASE_URL)
                    .client(client)
                    //然后将下面的GsonConverterFactory.create()替换成我们自定义的ResponseConverterFactory.create()
    //                .addConverterFactory(ResponseConverterFactory.create())
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
    
        public static RetrofitUtils getInstance() {
            if (apiEngine == null) {
                synchronized (RetrofitUtils.class) {
                    if (apiEngine == null) {
                        apiEngine = new RetrofitUtils();
                    }
                }
            }
            return apiEngine;
        }
    
        public ApiService getApiService() {
            return retrofit.create(ApiService.class);
        }
    
    }
    

    这段代码是对Retrofit进行封装并添加了拦截器,当我把 .addInterceptor(loggingInterceptor)这一行注释掉以后,奇迹出现了。点击注册后竟然神奇般的注册成功了!(发现了问题所在,兴奋至极啊,真的就差一点就放弃了!)注意这行代码,是为Retrofit添加了日志拦截器!继续跟进代码看这个拦截器的内容,经过调试发现竟然是因为HttpLoggingInterceptor 中setLevel
    的一行代码导致的,即loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    这行代码。于是试了试把BOEY改成了HEADERS后再试测发现这个异常就没有再出现了!但是改过之后日志拦截器会有些问题,就是只能拦截请求头的日志,请求体中的日志无法拦截,其实已经失去了拦截日志的意义了!但是这个问题终归解决了。只需要改一个单词或者去掉日志拦截器!修改后是这样的:loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);

    相关文章

      网友评论

          本文标题:Retrofit 上传图片的坑

          本文链接:https://www.haomeiwen.com/subject/guxvgftx.html