【okhttp】小问题记录合集

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修改开放权限

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

刷题之和为k的数组(leetcode)

和为k的数组 这个思路一直想不到&#xff0c;参考了官方答案&#xff0c;哈希表记录[0,i]的和 class Solution { public:int subarraySum(vector<int>& nums, int k) {int result0;unordered_map<int, int>map;int pre0;//前缀和&#xff08;前面的和&…

【Qt 学习笔记】Qt窗口 | Qt窗口介绍 | QMainwindow类及各组件介绍

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | Qt窗口介绍 | QMainwindow类及各组件介绍 文章编号&#xff…

图数据库助力供应链柔性升级

导读 当今市场环境受短视频等流媒体影响&#xff0c;任何风险事件在社交网络中传播速度极其迅速&#xff0c;留给企业的反应时间按分秒计&#xff0c;传统供应链的年度计划面对剧烈变化的市场环境已失去意义。此外&#xff0c;受近年局势动荡的影响&#xff0c;市场需求和供应…

为了性能,放弃tft_eSPI,选择arduino_gfx吧

本来对于tft_espi和arduino_gfx没啥特别的感觉&#xff0c;都是tft屏幕驱动,arduino_gfx的好处就是除了支持tft外还支持一些oled屏幕。 谁知道在探寻我那个在单片机项目上显示中文方案 https://github.com/StarCompute/tftziku 时候&#xff0c;寻求极致性能测了一些东西。 t…

3---版本库和工作区、使用.git管理工作区的文件、HEAD指针和master的关系

一、本地仓库和工作区的概念&#xff1a; 1.1本地仓库——版本库&#xff1a; 本地仓库又称为版本库。版本库是隐藏目录.git&#xff0c;并不是.git所在的目录。版本库不属于工作区。我们不能手动操作.git目录及其中的文件&#xff0c;这样可能会直接破坏版本库。stage(暂存区…

解决Flutter位于悬浮窗口时,应用Logo不更新问题

问题描述 我已经更换了应用Logo&#xff0c;但是发现应用处于悬浮窗口时&#xff0c;logo还是更改之前的&#xff1f;下面的图片只是示意。 解决方案 终端命令 rm -rf ~/Library/Developer/Xcode/DerivedData2.xcode视图内解决 先在顶部找到 Xcode --> Setting --> Lo…

第十九届全国环境友好科技竞赛(绿色创业类)正式启动

近日&#xff0c;第十九届全国环境友好科技竞赛&#xff08;绿色创业类&#xff09;正式拉开帷幕。本次竞赛由清华大学、同济大学、西安建筑科技大学及中国环境科学学会共同主办&#xff0c;旨在通过学科竞赛的方式鼓励全国高校学生积极参与到资源节约型和环境友好型的和谐社会…

docker搭建私有仓库并推送本地镜像

1、私仓搭建 docker pull registry#拉取镜像 docker images#查看镜像 mkdir -p /czx/myregistry 创建挂载目录 运行私有库registry (相当于本地有个是有docker hub) docker run -d -p 5000:5000 -v /czx/myregistry/:/tmp/registry --restartalways --privilegedtrue regist…

[技术报告]InternLM2 Technical Report

摘要 像ChatGPT和GPT-4这样的大型语言模型&#xff08;llm&#xff09;的进化引发了人们对人工通用智能&#xff08;AGI&#xff09;出现的讨论。然而&#xff0c;在开源模型中复制这种进步一直是一个挑战。本文介绍了InternLM2&#xff0c;这是一个开源的大语言模型&#xff…

惊呆了!企业数字化转型竟如工厂生产?

在众多使用蚓链数字化生态系统解决方案实现数字化转型的企业&#xff0c;你能想象吗&#xff1f;如今的企业数字化转型&#xff0c;就如同一家工厂的生产过程&#xff01;数据成为了原材料&#xff0c;而数据资源则是场景化的零件&#xff0c;最终生产出满足市场需求的数据产品…

7. Spring MVC面试题汇总

Java全栈面试题汇总目录-CSDN博客 1. 什么是Spring MVC&#xff0c;简单介绍下你对Spring MVC的理解? Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进…

【论文阅读】AID(ICCV‘23)

paper:https://arxiv.org/abs/2310.05666 code:https://github.com/YilongLv/AID Anchor-Intermediate Detector: Decoupling and Coupling Bounding Boxes for Accurate Object Detection

RT-Thread Env开发探索——以HC-SR04超声波传感器为例

RT-Thread Env开发探索——以HC-SR04超声波传感器为例 0.前言一、BSP优化1.修改芯片功能配置2.修改RTT配置菜单 二、软件包加载1.外设配置2.驱动框架配置3.软件包配置 三、编译及运行四、源码分析五、总结 参考文章&#xff1a;RT Thread Env CLion环境搭建 0.前言 对比使用R…

文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失

文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失 文章目录 文件自动同步备份-FreeFileSync工具解决硬盘损坏、误操作覆盖导致数据丢失前言一、FreeFileSync二、使用方法1.用外部存储卡或盘作为异地备份目标盘2.设置同步策略3.设置为windows的自动计划 …

在数据中心网络中隔离大象流

1000 条短突发中混入几条大象流将严重影响短突发 p99 latency&#xff0c;造成抖动。这个我在 隔离网络流以优化网络 论证过了&#xff0c;还有另一种更直观的理解方式&#xff1a; 规模差异越大&#xff0c;算术均值越偏离中位数&#xff0c;即算术均值的分位数越高。 可以…

Redis 源码学习记录:散列 (dict)

散列 Redis 源码版本&#xff1a;Redis-6.0.9&#xff0c;本篇文章的代码均在 dict.h / dict.c 文件中。 散列类型可以存储一组无需的键值对&#xff0c;他特别适用于存储一个对象数据。 字典 Redis 通常使用字典结构体存储用户散列数据。字典是 Redis 的重要数据结构。除了散…

DNS服务的部署与配置(1)

一、DNS的定义 1、域名系统&#xff08;英文&#xff1a;Domain Name System&#xff0c;缩写&#xff1a;DNS&#xff09;是互联网的一项服务。 它作为将域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使人更方便地访问互联网。 DNS使用UDP端口53。 当前&#xff0…

AUTOMATIC1111/stable-diffusion-webui/stable-diffusion-webui-v1.9.3

配置环境介绍 目前平台集成了 Stable Diffusion WebUI 的官方镜像&#xff0c;该镜像中整合如下资源&#xff1a; GpuMall智算云 | 省钱、好用、弹性。租GPU就上GpuMall,面向AI开发者的GPU云平台 Stable Diffusion WebUI版本&#xff1a;v1.9.3 Python版本&#xff1a;3.10.…

一维前缀和[模版]

题目链接 题目: 分析: 因为要求数组中连续区间的和, 可以使用前缀和算法注意:下标是从1开始算起的, 真正下标0的位置是0第一步: 预处理出来一个前缀和数组dp dp[i] 表示: 表示[1,i] 区间所有元素的和dp[i] dp[i-1] arr[i]例如示例一中: dp数组为{1,3,7}第二步: 使用前缀数…

02_前端三大件HTML

文章目录 HTML用于网页结构搭建1. 标签2. 客户端服务器交互流程3. 专业词汇4. html语法细节5. 安装VSCODE安装插件6. Live Server插件使用7. 标题&段落&换行&列表8. 超链接标签使用9. 图片10. 表格的写法11. 表单标签*(重点)12. 下拉框13. 页面布局标签14. 块元素和…