【okhttp】小问题记录合集

news2024/12/25 1:31:31

can’t create native thread

问题描述

OkHttpClient 每次使用都new创建,造成OOM,提示can’t create native thread…

问题分析
没有将OkHttpClient单例化.
每个client对象都有自己的线程池和连接池,如果为每个请求都创建一个client对象,自然会出现内存溢出。所以官方建议OkHttpClient应该单例化,重用连接和线程能降低延迟和减少内存消耗。

问题解决

使用官方推荐的方式,按需创建实例。

  1. new OkHttpClient()
    该方式将创建一个使用默认设置的client单例对象。
  2. new OkHttpClient.Builder()
    该方式允许自定义配置自己的单例client对象。配置connectionTimeout, readTimeout, writeTimeout等参数。
     okHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(50L, TimeUnit.SECONDS)
                            .readTimeout(60L, TimeUnit.SECONDS)
                            .build();
    
    
  3. okHttpclient.newBuilder()
    该方式通过已经存在的client对象,创建特殊需要的client对象。如 我们通过上个方法创建了自定义配置的单例client对象,但是针对某些场景需要调整某些参数,那么就需要使用该方法创建定制的client。新client对象与旧client对象共享连接池,线程池和其他配置。
    OkHttpClient myClient = okHttpClient.newBuilder()
                            .readTimeout(80L, TimeUnit.SECONDS).build();
    
    

get不支持请求体

问题描述

使用Retrofit发送get请求,自定义的service传递了实体bean对象,出现cras

@HTTP(method = "GET",path = "extend-web/intelligence-recipe/queryByModel",hasBody = true)
Call<CookResponse> postCookBook(@Body CookBookRequestBean cookBook);

问题分析

Retrofit自带的Okhttp内部报的错,主要原因是在HttpMethod#permitsRequestBody,判断get方法是否包含请求体,如果包含,就抛出异常;所以get请求发不出去。
Retrofit自带的okhttp不支持带body的get,想跳过那句请求体检查,可以通过修改源码方式解除判断;
Http协议只支持get请求path形式访问,不支持get请求带请求体的,所以即使你修改Okhttp源码,解除了get方法判断是否包含请求体,,也无法从应用层-…—网络层-链路层一层一层的将参数传递到server,更别说进入Tomcat,让Spring框架解析你的参数了;

一句话总结:Http协议规定get请求只能path形式进行查询;Retrofit+Okhttp遵循了Http协议规范,所以抛出异常,强制开发者使用Post协议发请求体。

问题解决

  1. get不传递请求体
  2. 修改body源码,在okhttp组装的时候用post格式组装,发出请求的时候用get请求发出

 
 #为了okhttp支持GET RequestBody
 -keepclassmembers public class okhttp3.Request {
    *** method;
  }
 
 
/**
 * 让okhttp get请求支持body
 */
public class FixGetWithBody {
    public static final String HEADER_KEY = "real_method";
    public static final String HEADER_VALUE = "GET";
    public static final String HEADER = HEADER_KEY + ": " + HEADER_VALUE;
    static ThreadLocal<Request> sThreadLocal = new ThreadLocal<>();
// TODO 第一步,在请求的时候,使用POST方式构造request,并且header里增加 HEADER_KEY,HEADER_VALUE,用来表示实际走GET请求
    /**
     * 添加到okhttp里
     *
     * @return
     */
    public static Interceptor getInterceptor() {
        return new InterceptorImpl();
    }
 
    /**
     * 添加到okhttp里
     */
    public static EventListener getEventListener() {
        return new EventListenerImpl();
    }
 
    private static boolean needConvertToGet(Request request) {
        if (request == null) {
            return false;
        }
        return HEADER_VALUE.equalsIgnoreCase(request.header(HEADER_KEY));
    }
 
    private static void changeMethod(String method) {
        Request request = sThreadLocal.get();
        if (request != null) {
            try {
                Field field = Request.class.getDeclaredField("method");
                field.setAccessible(true);
                field.set(request, method);
            } catch (IllegalAccessException | NoSuchFieldException e) {
            }
        }
    }
 
    private static class EventListenerImpl extends EventListener {
 
        @Override
        public void requestHeadersStart(Call call) {
            super.requestHeadersStart(call);
            // 在发送header之前,改回GET,这一步为了让服务端收到GET请求
            changeMethod("GET");
        }
 
        @Override
        public void requestHeadersEnd(Call call, Request req) {
            super.requestHeadersEnd(call, req);
            // 为了让okhttp发送body,需要改为post,跳过get校验(因为post请求OKHTTP底层才发送body)
            // 不过此时header已经发送完成,改回POST也无妨。
            changeMethod("POST");
            
            sThreadLocal.remove();
        }
    }
 
    private static class InterceptorImpl implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            RealInterceptorChain realChain = (RealInterceptorChain) chain;
            Request request = realChain.request();
            if (needConvertToGet(request)) {
                request = request.newBuilder().removeHeader(HEADER_KEY).build();
                sThreadLocal.set(request);
            }
            return chain.proceed(request);
        }
    }
}

urlencode编码二次的问题The valid characters are defined in RFC 7230 and RFC 3986

问题描述
客户端发出的请求,服务端解析异常

问题分析

1.是TOMCAT报的错
2.和请求参数有关

问题解决
方法一:将json数据进行urlencode编码;
方法二:降低tomcat版本;
方法三:配置tomcat/conf下的catalina.properties

@Query注解默认将实体进行urlencode编码
使用@Query注解时,配置参数
如@Query(value=“”,encoded=true)
- encoded = true表示已经编码,无需让retrofit编码
encoded = false表示未编码,retrofit按情况编码

header不支持中文

问题描述

与后台协商协议,需要传递header参数,header的key-value存在中文,传递给后台,后台解析失败

问题分析

okhttp3 中 header 是不支持中文的

问题解决
URLEncoder编码传递中文,让后台用URLEncoder解码

java.lang.IllegalArgumentException: Could not locate call adapter for io.reactivex.Observable异常分析及解决

问题描述

新项目使用reftrofit与rxjava封装网络,报错Could not locate call adapter for io.reactivex.Observable

问题分析

rxjava版本不对,与retrofit不匹配

问题解决
选择合适的rxjava版本
在这里插入图片描述

回调都在子线程

问题描述
安卓不允许在子线程刷新ui;okhttp的callback回调仍然在子线程

问题分析

Call.enqueue(Callback cb),但是要注意 Callback 回调里面的方法全部是在子线程的。

问题解决

在主线程刷新ui,使用handler或者runOnUiThread

SocketTimeoutException或UnknownHostException

问题描述

请求http2.0,偶现UnknownHostException、SocketTimeoutException错误

问题分析
http1.1 支持 TCP 通道复用机制,http2.0 还支持了多路复用机制。
一般都是后台接口没有严格按照http1.1协议和http2.0协议来,导致服务器Socket关了,但是没有通知客户端,客户端下次请求,复用链路导致 SocketTimeoutException

问题解决

第一种:服务器端修改。

第二种:客户端关闭连接池 OkHttpClient.connectionPool().evictAll()。

第三种:客户端加重试机制,失败重新请求一次。推荐这种方式,失败重试可以解决很多其他网络偶然问题,比如快速切网的时候。

java.lang.SecurityException: Permission denied (missing INTERNET permission?)

问题描述

已经动态申请网络权限,还是报权限拒绝的错误,导致crash

问题分析

rom禁用了某个app的流量;rom禁止了app网络,看似给权限了,实际没给。

问题解决

识别到禁用后,捕获并提示用户,避免crash

// 添加 Interceptor 拦截器
public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = null;
                try {
                    response = chain.proceed(request);
                } catch (Throwable e) {
                    throw new IOException(e);
                }
                return response;
 }

联系rom修改开放权限

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1687396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java设计模式 _行为型模式_中介者模式

一、中介者模式 1、中介者模式 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为型模式。主要通过一个中介类&#xff0c;该类通常处理不同类之间的通信&#xff0c;并支持松耦合&#xff0c;使代码易于维护。 2、实现思路 &#xff08;1&#xff09;、定义实体…

入门级指纹密码智能锁方案简析以及适用芯片SSD210介绍

上篇我们大概讲了一下门锁的发展历史&#xff0c;近几年家用智能门锁行业中近几年的市场增长变化&#xff0c;举例说明了智能猫眼门锁在类市场份额最大的产品的一些技术参数以及芯片功能框架。 智能猫眼锁核心解决方案以及适用的芯片推荐简介https://blog.csdn.net/Chipsupply…

基于Pytorch的卷积神经网络MNIST手写数字识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 手写数字识别是计算机视觉和模式识别领域的一个经典问题。MNIST数据集是一个包含大量手写数字图片的…

军工单位如何做到安全跨网文件交换与导出的

在现代信息化战争中&#xff0c;军工单位在信息安全方面的需求尤为突出。跨网文件交换与导出作为军工单位日常运营的重要环节&#xff0c;面临着网络带宽限制、数据安全风险、合规性要求和传输稳定性等挑战。下面&#xff0c;我们将从以下几个方面探讨军工单位如何实现安全、高…

【UE5.1 多线程 异步】“Async Blueprints Extension”插件使用记录

目录 一、异步生成Actor示例 二、异步计算示例 参考视频 首先需要在商城中下载“Async Blueprints Extension”插件 一、异步生成Actor示例 2. 创建一个线程类&#xff0c;这里要指定父类为“LongAsyncTask”、“InfiniteAsyncTask”、“ShortAsyncTask”中的一个 在线程类…

成品短视频APP源码搭建

在数字化时代&#xff0c;短视频已成为全球范围内的流行趋势&#xff0c;吸引了大量的用户和内容创作者。对于有志于进入短视频领域的企业和个人来说&#xff0c;成品短视频APP源码搭建提供了一条快速、高效的路径。本文将探讨成品短视频APP源码搭建的过程及其优势&#xff0c;…

sheng的学习笔记-docker部署Greenplum

目录 docker安装gp数据库 mac版本 搭建gp数据库 连接数据库 windows版本 搭建gp数据库 连接数据库 docker安装gp数据库 mac版本 搭建gp数据库 打开终端&#xff0c;输入代码&#xff0c;查看版本 ocker search greenplum docker pull projectairws/greenplum docker…

uni-starter创建App项目最全流程(日后还有其他功能会不断更新)

一、创建项目 在HbuilderX中点击创建项目&#xff0c;选择uni-starter模板&#xff0c;选择阿里云、Vue3&#xff0c;填写项目名称后点击创建。如果没有下载过uni-starter会自动下载该插件&#xff0c;如下图&#xff1a; 二、 创建云服务器并关联项目 如果是第一次使用&#…

Linux中gcc/g++的基本使用

目录 gcc/g的使用gcc/g是如何生成可执行文件的预处理编译汇编链接 库.o文件是如何与库链接的&#xff1f; debug版本和release版本 gcc/g的使用 在windows中&#xff0c;我们在VS中编写好了代码之后就可以直接在VS中对源码进行编译等操作后运行 而在Linux下&#xff0c;我们可…

C++_vector操作使用

文章目录 &#x1f680;1.1 vector介绍&#x1f680;1.2 vector的初始化&#x1f680;1.3 vector的常用内置函数&#x1f680;1.4 vector的遍历 &#x1f680;1.1 vector介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元…

领域知识 | 智能驾驶安全领域部分常见概论

Hi&#xff0c;早。 最近想买个新能源车&#xff0c;这个车吧相比于之前的内燃车&#xff0c;新能源车与外界的交互多了很多。比如娱乐的第三方应用&#xff0c;OTA升级等应用。 交互带来的便利越多&#xff0c;暴露的风险自然也就越大&#xff0c;相比于手机等消费者终端设备…

tomcat三级指导

版本 ./catalina.sh linux version.bat win 1.确认是否使用了tomcat管理后台 我们先找到配置文件&#xff1a;tomcat主目录下/conf/server.xml 可以查看到连接端口&#xff0c;默认为8080 然后查看manager-gui管理页面配置文件&#xff0c;是否设置了用户登录 配置文件…

【C语言回顾】动态内存管理

前言1. 动态内存管理初步概述2. malloc3. calloc4. realloc5. free6. 常见的动态内存错误7. 柔性数组8. 程序内存区域划分结语 #include<GUIQU.h> int main { 上期回顾: 【C语言回顾】联合和枚举 个人主页&#xff1a;C_GUIQU 专栏&#xff1a;【C语言学习】 return 一键…

人工智能再现大脑细胞导航的活动模式

人工智能再现大脑细胞导航的活动模式 李升伟 编译 深度学习算法可自发模拟特殊神经元的活动&#xff0c;这种神经元活动可以告诉我们在空间的位置。 大鼠使用被称为网格细胞的大脑细胞帮助它们导航&#xff0c;人工智能程序已经可以再现这种能力。 科学家已经使用人工智能来再…

网络初识 一

一、网络发展史 1.1 独立模式 最开始的网络,计算机之间是相互独立的. 比如,三个计算机分别存着各自的数据,A正在获取第一台计算机的数据,等要获取第二台计算机的数据时要移动到第二台计算机那里,B想要获取第一台计算机的数据,就要等A使用完. 1.2 网络互连 随着时代的发展,…

Codigger编码场景介绍(二):驾驶舱场景(Cockpit)

Codigger&#xff0c;一个专为开发人员设计的工具&#xff0c;致力于为不同的开发场景提供最佳的切换体验。Codigger囊括了多种场景&#xff0c;如传统场景、调试场景、设计器场景、驾驶舱场景以及纯净场景等。在上一篇文章中&#xff0c;我们介绍了传统场景模式&#xff0c;今…

Linux 应用入门(一)

1. 交叉编译 概念&#xff1a;在当前编译平台下&#xff0c;编译出来的程序能运行在体系结构不同的另一种目标平台上&#xff0c;但是编译平台本身却不能运行该程序。 为什么需要交叉编译&#xff1f; 速度&#xff1a;目标平台得运行速度比主机往往慢得多&#xff0c;因为许多…

Linux程序开发(十一):进程与进程间通信设计之趣味猫咪抓老鼠游戏

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

在未来你将何去何从?

在数字化的浪潮中&#xff0c;信息技术行业无疑是推动全球经济和社会发展的重要动力。随着科技的不断迭代与进步&#xff0c;云计算、大数据、人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;、5G通信和区块链等技术已经深入到我们生活的每一个角落&am…