学会这篇OkHttp,花了我一个通宵,也是值了!

OkHttp无限重试问题 经测试,此为okhttp低版本的bug,虽然okhttp也有最大重试次数的判断逻辑,但无法触达。a.腾讯云LBHTTP2协议默认最大的HEADER大小为4kb,数据超过最最大值后,LB直接拒绝并发送FIN包给调用方。而,调用方因请求数据并未发送完,所以会继续发送数据,LB4收到额外数据后,发送RESET包给调用方,故,okhttp。注:问题发生时,请求经过的链路为:xxx-tc-tke-prod->腾讯LB。值班同学收到反馈,xxx-tc-tke-prodd请求频繁超时导致页面查询超时问题。 阅读详情
引子

OkHttp 知名第三方网络框架SDK,使用简单,性能优秀,但是内核并不简单,此系列文章,专挑硬核知识点详细讲解。何为硬核,就是要想深入研究,你绝对绕不过去的知识点。

TIPS:声明:拦截器种细节太多,要一一讲解不太现实,所以我挑了其中最实用的一些要点加以总结。

详细讲解 OKHttp的核心内容,拦截器。不过拦截器众多,有系统自带的,也有我们可以自己去自定义的。

大家可以先看首篇-你必须学会的OKHttp
(顺手留下GitHub链接,需要获取相关面试或者面试宝典核心笔记PDF等内容的可以自己去找)
https://github.com/xiangjiana/Android-MS

更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取


这是网络请求执行的核心方法的起点,这里涉及了众多拦截器。

正文大纲
系统自带拦截器

1 重试与重定向拦截器 RetryAndFollowUpInterceptor
2 桥接拦截器
3 缓存拦截器 CacheInterceptor
4 连接拦截器 ConnectInterceptor
5 服务调用拦截器 CallServerInterceptor

正文

在详解拦截器之前,有必要先将 RealCall的 getResponseWithInterceptorChain() 方法最后两行展开说明:

  Interceptor.Chain chain = newRealInterceptorChain( interceptors, null, null, null, 0, originalRequest);
  return chain.proceed(originalRequest);

这里最终返回 一个 Response,进入 chain.proceed方法,最终索引到 RealInterceptorChain的 proceed方法:

之后,我们追踪这个 interceptor.intercept(next); ,发现是一个接口,找到实现类,有多个,进入其中的 RetryAndFollowUpInterceptor,发现:

它这里又执行了 chain.proceed,于是又回到了 RealInterceptorChain.proceed()方法,但是此时,刚才链条中的拦截器已经不再是原来的拦截器了,而是变成了第二个,因为每一次都 index+1了(这里比较绕,类似递归,需要反复仔细体会),依次类推,直到所有拦截器的intercept方法都执行完毕,直到链条中没有拦截器。就返回最后的 Response。

这一段是 okhttp责任链模式的核心,应该好理解

系统自带拦截器
1. 重试与重定向拦截器 RetryAndFollowUpInterceptor

先说结论吧:

顾名思义,retry 重试,FollowUp 重定向 。这个拦截器处在所有拦截器的第一个,它是用来判定要不要对当前请求进行重试和重定向的,
那么我们应该关心的是: 什么时候重试, 什么时候重定向。并且,它会判断用户有没有取消请求,因为RealCall中有一个cancel方法,可以支持用户 取消请求(不过这里有两种情况,在请求发出之 前取消,和 在之 后取消。如果是在请求之 前取消,那就直接不执行之后的过程,如果是在请求发出去之 后取消,那么客户端就会丢弃这一次的 response)

重试
RetryAndFollowUpInterceptor的核心方法 interceptor() :

  @Override public Response intercept(Chain chain) throws IOException {
    ...省略
    while (true) {
      ...省略
      try {
        response = ((RealInterceptorChain) chain).proceed(request,streamAllocation, null, null);
        releaseConnection = false;      
     } catch (RouteException e) {
        // The attempt to connect via a route failed. The request will not have been sent.
        if (!recover(e.getLastConnectException(), false, request)) {
          throw e.getLastConnectException();
        }
        releaseConnection = false;        continue;
      } catch (IOException e) {
        // An attempt to communicate with a server failed. The request may have been sent.
        boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
        if (!recover(e, requestSendStarted, request)) throw e;
        releaseConnection = false;
        continue;
      }
      ...省略
      if (followUp == null) {
        if (!forWebSocket) {
          streamAllocation.release();
        }
        return response;
      }
      ...省略

    }
  }

上面的代码中,我只保留了关键部分。其中有两个continue,一个return.
当请求到达了这个拦截器,它会进入一个 while(true)循环,

当发生了 RouteException 异常(这是由于请求尚未发出去,路由异常,连接未成功),就会去判断 recover方法的返回值,根据返回值决定要不要 continue.
当发生 IOException(请求已经发出去,但是和服务器通信失败了)之后,同样去判断 recover方法的返回值,根据返回值决定要不要 continue.
如果这两个 continue都没有执行,就有可能走到最后的 returnresponse结束本次请求. 那么 是不是要 重试,其判断逻辑就在 recover()方法内部:

  private boolean recover(IOException e, StreamAllocation streamAllocation,
                            boolean requestSendStarted, Request userRequest) {
        streamAllocation.streamFailed(e);

        //todo 1、在配置OkhttpClient是设置了不允许重试(默认允许),则一旦发生请求失败就不再重试
        //The application layer has forbidden retries.
        if (!client.retryOnConnectionFailure()) return false;

        //todo 2、由于requestSendStarted只在http2的io异常中为false,http1则是 true,
        //在http1的情况下,需要判定 body有没有实现UnrepeatableRequestBody接口,而body默认是没有实现,所以后续instanceOf不成立,不会走return false.
        //We can't send the request body again.
        if (requestSendStarted && userRequest.body() instanceof UnrepeatableRequestBody)
            return false;

        //todo 3、判断是不是属于重试的异常
        //This exception is fatal.
        if (!isRecoverable(e, requestSendStarted)) return false;

        //todo 4、有没有可以用来连接的路由路线
        //No more routes to attempt.
        if (!streamAllocation.hasMoreRoutes()) return false;

        // For failure recovery, use the same route selector with a new connection.
        return true;
    }

简单解读一下这个方法:

  • 如果okhttpClient已经set了不允许重试,那么这里就返回false,不再重试。
  • 如果requestSendStarted 只在http2.0的IO异常中是true,不过HTTP2.0还没普及,先不管他,这里默认通过。
  • 判断是否是重试的异常,也就是说,是不是之前重试之后发生了异常。这里解读一下,之前重试发生过异常,抛出了Exception,这个 isRecoverable方法会根据这个异常去判定,是否还有必要去重试。
  • 协议异常,如果发生了协议异常,那么没必要重试了,你的请求或者服务器本身可能就存在问题,再重试也是白瞎。
  • 超时异常,只是超时而已,直接判定重试(这里requestSendStarted是http2才会为true,所以这里默认就是false)
  • SSL异常,HTTPS证书出现问题,没必要重试。
  • SSL握手未授权异常,也不必重试
  private boolean isRecoverable(IOException e, boolean requestSendStarted) {
    // 出现协议异常,不能重试
    if (e instanceof ProtocolException) {
      return false;
    }

    // requestSendStarted认为它一直为false(不管http2),异常属于socket超时异常,直接判定可以重试
    if (e instanceof InterruptedIOException) {
      return e instanceof SocketTimeoutException && !requestSendStarted;    
    }

    // SSL握手异常中,证书出现问题,不能重试
    if (e instanceof SSLHandshakeException) {
      if (e.getCause() instanceof CertificateException) {
        return false;
      }
    }
    // SSL握手未授权异常 不能重试
    if (e instanceof SSLPeerUnverifiedException) {
      return false;    }
    return true;
}

有没有可以用来连接的路由路线,也就是说,如果当DNS解析域名的时候,返回了多个IP,那么这里可能一个一个去尝试重试,直到没有更多ip可用。

重定向
依然是 RetryAndFollowUpInterceptor的核心方法 interceptor() 方法,这次我截取后半段:

  public Response intercept(Chain chain) throws IOException {
     while (true) {
            ...省略前面的重试判定
            //todo 处理3和4xx的一些状态码,如301 302重定向
            Request followUp = followUpRequest(response, streamAllocation.route());
            if (followUp == null) {
                if (!forWebSocket) {
                    streamAllocation.release();
                }
                return response;
            }

            closeQuietly(response.body());

            //todo 限制最大 followup 次数为20次
            if (++followUpCount > MAX_FOLLOW_UPS) {
                streamAllocation.release();
                throw new ProtocolException("Too many follow-up requests: " + followUpCount);
            }

            if (followUp.body() instanceof UnrepeatableRequestBody) {
                streamAllocation.release();
                throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
            }
            //todo 判断是不是可以复用同一份连接
            if (!sameConnection(response, followUp.url())) {
                streamAllocation.release();
                streamAllocation = new StreamAllocation(client.connectionPool(),
                       createAddress(followUp.url()), call, eventListener, callStackTrace);
                this.streamAllocation = streamAllocation;
            } else if (streamAllocation.codec() != null) {
                throw new IllegalStateException("Closing the body of " + response
                        + " didn't close its backing stream. Bad interceptor?");
            }
     }
 }

上面源码中, followUpRequest() 方法中规定了哪些响应码可以重定向:

  private Request followUpRequest(Response userResponse) throws IOException {
    if (userResponse == null) throw new IllegalStateException();
    Connection connection = streamAllocation.connection();
    Route route = connection != null
        ? connection.route()
        : null;
    int responseCode = userResponse.code();

    final String method = userResponse.request().method();
    switch (responseCode) {
      // 407 客户端使用了HTTP代理服务器,在请求头中添加 “Proxy-Authorization”,让代理服务器授权
      case HTTP_PROXY_AUTH:
          Proxy selectedProxy = route != null
            ? route.proxy()
            : client.proxy();
        if (selectedProxy.type() != Proxy.Type.HTTP) {
          throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy");
        }
        return client.proxyAuthenticator().authenticate(route, userResponse);
      // 401 需要身份验证 有些服务器接口需要验证使用者身份 在请求头中添加 “Authorization”
      case HTTP_UNAUTHORIZED:
        return client.authenticator().authenticate(route, userResponse);
      // 308 永久重定向
      // 307 临时重定向
      case HTTP_PERM_REDIRECT:
      case HTTP_TEMP_REDIRECT:
        // 如果请求方式不是GET或者HEAD,框架不会自动重定向请求
        if (!method.equals("GET") && !method.equals("HEAD")) {
          return null;
        }
      // 300 301 302 303
      case HTTP_MULT_CHOICE:
      case HTTP_MOVED_PERM:
      case HTTP_MOVED_TEMP:
      case HTTP_SEE_OTHER:
        // 如果用户不允许重定向,那就返回null
        if (!client.followRedirects()) return null;
        // 从响应头取出location
        String location = userResponse.header("Location");
        if (location == null) return null;
        // 根据location 配置新的请求 url
        HttpUrl url = userResponse.request().url().resolve(location);
        // 如果为null,说明协议有问题,取不出来HttpUrl,那就返回null,不进行重定向
        if (url == null) return null;
        // 如果重定向在http到https之间切换,需要检查用户是不是允许(默认允许)
        boolean sameScheme =url.scheme().equals(userResponse.request().url().scheme());
        if (!sameScheme && !client.followSslRedirects()) return null;

        Request.Builder requestBuilder = userResponse.request().newBuilder();
        /**
         *  重定向请求中 只要不是 PROPFIND 请求,无论是POST还是其他的方法都要改为GET请求方式,
         *  即只有 PROPFIND 请求才能有请求体
         */
        //请求不是get与head
        if (HttpMethod.permitsRequestBody(method)) {
          final boolean maintainBody = HttpMethod.redirectsWithBody(method);
           // 除了 PROPFIND 请求之外都改成GET请求
          if (HttpMethod.redirectsToGet(method)) {
            requestBuilder.method("GET", null);
          } else {
            RequestBody requestBody = maintainBody ? userResponse.request().body() : null;
            requestBuilder.method(method, requestBody);
          }
          // 不是 PROPFIND 的请求,把请求头中关于请求体的数据删掉
          if (!maintainBody) {
            requestBuilder.removeHeader("Transfer-Encoding");
            requestBuilder.removeHeader("Content-Length");
            requestBuilder.removeHeader("Content-Type");
          }
        }

        // 在跨主机重定向时,删除身份验证请求头
        if (!sameConnection(userResponse, url)) {
          requestBuilder.removeHeader("Authorization");
        }

        return requestBuilder.url(url).build();

      // 408 客户端请求超时
      case HTTP_CLIENT_TIMEOUT:
        // 408 算是连接失败了,所以判断用户是不是允许重试
           if (!client.retryOnConnectionFailure()) {
            return null;
        }
        // UnrepeatableRequestBody实际并没发现有其他地方用到
        if (userResponse.request().body() instanceof UnrepeatableRequestBody) {
            return null;
        }
        // 如果是本身这次的响应就是重新请求的产物同时上一次之所以重请求还是因为408,那我们这次不再重请求了
        if (userResponse.priorResponse() != null
                       &&userResponse.priorResponse().code()==HTTP_CLIENT_TIMEOUT) {
            return null;
        }
        // 如果服务器告诉我们了 Retry-After 多久后重试,那框架不管了。
        if (retryAfter(userResponse, 0) > 0) {
            return null;
        }
        return userResponse.request();
       // 503 服务不可用 和408差不多,但是只在服务器告诉你 Retry-After:0(意思就是立即重试) 才重请求
        case HTTP_UNAVAILABLE:
        if (userResponse.priorResponse() != null
                        && userResponse.priorResponse().code() == HTTP_UNAVAILABLE) {
             return null;
         }

         if (retryAfter(userResponse, Integer.MAX_VALUE) == 0) {
             return userResponse.request();
         }

         return null;
      default:
        return null;
    }
}

解读一下这个方法,它根据拿到的response的内容,判断他的响应码,决定要不要返回一个新的request,如果返回了新的request,那么外围( 看RetryAndFollowUpInterceptor的intercept方法)的 while(true)无限循环就会 使用新的request再次请求,完成重定向。细节上请查看上面代码的注释,来自一位高手,写的很详细。大概做个结论:

  • 响应码 3XX 一般都会返回一个 新的Request,而另外的 return null就是不允许重定向。
  • followup最大发生20次

不过还是那句话,我们不是专门做网络架构或者优化,了解到 这一个拦截器的基本作用,重要节点即可,真要抠细节,谁也记不了那么清楚。

2. 桥接拦截器 BridgeInterceptor

这个可能是这5个当中最简单的一个拦截器了,它从上一层RetryAndFollowUpInterceptor拿到 request之后,只做了一件事: 补全请求头我们使用OkHttp发送网络请求,一般只会 addHeader中写上我们业务相关的一些参数,而 真正的请求头远远没有那么简单。服务器不只是要识别 业务参数,还要识别 请求类型,请求体的解析方式等,具体列举如下:

它在补全了请求头之后,交给下一个拦截器处理。在它得到响应之后,还会干两件事:
1、保存cookie,下一次同样域名的请求就会带上cookie到请求头中,但是这个要求我们自己在okHttpClient的CookieJar中实现具体过程。

如果使用gzip返回的数据,则使用GzipSource包装便于解析。

3. 缓存拦截器 CacheInterceptor

本文只介绍他的作用,因为内部逻辑太过复杂,必须单独成文讲解。

更多完整项目下载。未完待续。源码。图文知识后续上传github。
可以点击关于我联系我获取

OKHttp3源码分析——学习笔记 文章目录1. HttpClient与HttpUrlConnection的区别2. OKHttp源码分析使用步骤:dispatcher任务调度器,Request请求RealCallAsyncCall3. OKHttp架构分析1. 异步请求线程池, Dispather2. 连接池清理线程池- ConnectionPool3. 缓存整理线程池 DisLruCache4. Http2异步事务线程池, ht... 阅读详情

相关推荐

深入解读OKhttp五大拦截器之RetryAndFollowUpInterceptor

Okhttp的封装了一些列请求所需要的参数,不管是同步请求还是异步请求最终都会经过五大拦截器的处理才能得到服务器返回的请求结果。本篇文章主要讲解Okhttp五大拦截器的重试重定向拦截器的作用。RetryAndFollowUpInterceptor拦截器作为OKhttp的第一个默认拦截器,主要作用是当客户端网络请求失败时或目标响应的位置发生改变时调用。

jiakuize2291的博客 1207

Okhttp容错机制的坑

OKHttp内部是做了失败从连的操作的,那么我就来简单看下失败重连的相关逻辑。 从源码RetryAndFollowUpInterceptor#intercept方法说起 因为是失败从连,所以我们要看cacth相关部分的代码,代码如下: ① catch (RouteException e) {    // The attempt to connect via a route

Ztw的博客 1万+

【Android】实现登录、注册、数据库操作(极复杂)

前言 实现效果如下 项目源代码GitHub地址(源码中有详细注释):https://github.com/littlecurl/LoginDemo apk下载体验地址(2019年7月之后服务器到期就不能体验了):…明天我把它放服务器再更新 ### 交代一些资源 我曾经写过一篇受大家欢迎的博客: 【Android】实现登录、注册、数据库操作(极简洁) 现在这篇文章是原先那篇的升级版,实现了前后端...

midnight_time的博客 4万+

Okhttp首次访问接口超时的分析以及解决办法

问题重现 开发的一款app,网络访问框架是okhttp。在内网测试,需要设定dns,连接wifi,设置dns,测试为了抓包,wifi设置了代理。问题:首次访问接口,会超时,后续访问接口速度就很快,间隔一段时间不访问,访问接口也会超时,抓包显示,服务器很快就返回了数据,有时候会连续返回两条。 我的okhttp配置 ClearableCookieJar cookieJar1 = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCooki

jifashihan的博客 1万+

SpringCloud OpenFeign Content-Length 透传陷阱与 RequestInterceptor 精准拦截方案

本文深入分析了SpringCloud OpenFeign中Content-Length透传导致的'too many bytes written'异常问题,揭示了HttpURLConnection严格校验机制背后的原理。针对微服务调用链中的Content-Length陷阱,提供了从基础过滤到动态计算的RequestInterceptor精准拦截方案,并推荐结合OkHttp客户端实现最佳实践,帮助开发者有效规避这一常见但易被忽视的微服务通信问题。

weixin_26985923的博客 386

Android拍照识花App源码,集成百度AI植物识别API,支持相册选图与实时结果展示

这个Android应用源码能直接运行,主打拍照或从手机相册选图识别花草树木。背后调用的是百度AI开放平台的植物识别接口,上传图片后返回植物中文名、识别置信度、百科链接等结构化信息。项目基于Android Studio标准结构开发,已适配Android 6.0及以上系统,完整处理相机权限、存储权限等动态授权逻辑;内置网络请求封装(含错误重试与状态提示)、简洁UI界面(含相机预览页、图片查看页、识别结果列表页)以及基础异常捕获机制。代码中预留了API Key和Secret Key的配置入口,开发者只需在指定Ja

s3t4u的博客 283

Android最全学会这篇OkHttp,花了我一个通宵,也是值了!,2024年最新安卓开发页面设计

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。还有。

2401_84520215的博客 314

安卓新闻App源码实战:从环境配置到功能扩展的完整指南

Android应用开发中,RecyclerView与网络请求是构建新闻客户端的基础技术。通过Adapter绑定数据、OkHttp获取接口、Glide加载图片,开发者能快速实现列表展示与详情跳转。这些技术不仅提升开发效率,还能灵活应对分类切换、本地JSON解析等场景。本文以一份完整的安卓新闻App源码为例,详解环境配置、模块修改与避坑技巧,助你高效完成期末大作业。

weixin_28839549的博客 248

通宵都要看完这个Android关键技术点,面试资料分享

前言 前几年移动互联网创业的风口,如今渐渐消失,移动互联网被巨头公司瓜分,一些创业公司倒闭了,Android 开发需求慢慢趋近于饱和。而当初移动互联网处于风口时,自学、转行以及培训机构出来了大量 Android 开发从业者,导致目前看起来市场供大于求。 那么 Android 开发工程师们应该如何面对当下的局面呢? 其实当下的供需关系不平衡不代表没有需求,市场上过多的是只会写 xml 和 Activity、只会用代码堆需求的初级 Android 程序员,而高级&nbsp

fanzhang_vip0723的博客 146

群晖NAS从入门到精通的所有帖子汇总,只要这一篇就够了

本站陆陆续续的转载、原创帖子也有十几二十篇了,从不同的角度对群晖NAS的各种骚操作都有深入的讲解,虽然很多文章都不是讲的很深入,但是针对小白入门已经是足够了,希望对小白来说是一个入门,群晖NAS的大佬们勿喷,哪里写的不对的,请随时留言西安SEO优化站长一定在第一时间纠正修改。

西安SEO优化网站资源 8万+

OpenClaw:深度学习驱动的智能编程工具实战解析

智能编程工具通过深度学习技术革新传统开发流程,其核心在于代码语义理解与实时协作能力。这类工具采用AI代码补全、错误预测等技术,显著降低开发者认知负荷,尤其适用于复杂业务逻辑开发和遗留系统维护场景。以OpenClaw为例,其智能填充和上下文感知功能可提升40%编码效率,减少65%调试时间。关键技术实现包含自然语言处理、代码静态分析等,在金融科技、电商系统等领域具有广泛应用前景。热词提示:代码理解引擎、智能工作流整合展现了当前AI辅助开发的最新趋势。

chubaisheng8627的博客 320

Android一揽子学习文章,都在这里了

Android、Java、Kotlin、Jetpack、计算机网络、数据结构......

flyzhuzhu7 2128

Android图形系统(三)系统篇:渲染/合成的底层原理浅析

众所周知,渲染工作是由GPU负责,那么在聊GPU之前首先得知道什么是“渲染”?我们来举个例子感受一下在系统中申请一块10*101、把图层背景这玩意染成绿的2、从左上(0,0)到右下(10,10)画一条宽度为1颜色为红色的直线3、以坐标点(5,5)为中心,画一个半径为3的实心圆,颜色要蓝色好了,接下来操作系统会把这些“绘图指令”同步给GPU去执行渲染任务图片来源:自己画的GPU完成渲染工作后,我们将会得到一个大小为10*10二维数组,数组中的每个元素都保存着坐标点的颜色信息、深度信息。

1358

第一次!

刚刚开通了优快云的博客,以前也只是看别人的,感觉无论是转载还是翻译都能给我的项目开发带来很大的帮助,特别是一些把直接开发的进度写成博客记录的人!对很多新手会有很多帮助,让他们发现还有很多人在一步一步的行走在开发的这条道路上!而对于写博客的本人也会起到自我总结规划提高的作用!特别是在这里不需要美丽的文字,严谨的逻辑,你只需写出自己实实在在实现的过程。与此同时,高手会指正,新手会“膜拜”。大家就在这

ddmm45的专栏 344

第78章:PCL Multiple View ICP 多视角配准

多视角配准(Multiple View ICP)是迭代最近点(ICP)算法的扩展,旨在处理多视角的点云数据配准问题。传统的ICP算法主要用于两幅点云之间的配准,而多视角配准则处理来自多个视角或不同时间采集的多个点云数据的配准任务。在实际应用中,多个传感器或多个拍摄角度获得的点云数据常常需要进行联合配准。这些点云可能由于不同的视角、拍摄位置或时间差异而存在位置和旋转的差异。多视角配准的目标是根据多个点云之间的匹配关系,找到它们的相对变换,使得这些点云能够合并成一个统一的三维模型。

yumeiguo的博客 158

学Simulink——基于软开关与高频变换的整流器系统场景实例:移相全桥ZVS整流器在轻载条件下的效率优化

本文以Simulink为平台,详细介绍了移相全桥ZVS整流器在轻载条件下的建模与优化方法。通过六个步骤系统讲解了从项目创建到仿真运行的全过程,重点分析了移相全桥拓扑结构、ZVS检测逻辑设计及轻载特性。结果显示,传统移相全桥在轻载时ZVS失效导致效率下降(<88%)。针对此问题,提出了动态频率调整、不对称半桥模式等优化策略。该案例为理解软开关技术、提升电源效率提供了实用建模方法和优化思路。

xiaoheshang_123的博客 117

一线互联网大厂面试真题系统收录!成功入职腾讯

前言 “金三银四”再过几天就到了,又到了一年一度的大型**“程序猿跳槽大会”**。作为大龄IT从业者的我们,每到这个时候就会想起年轻时的自己,为了能搞定面试官,通宵背题库,背定义,四处收集面试真题…每次都准备的满满当当,可一到了面试的时候,就会发现与自己预想的完全不一样。 直到后来经历了这么多年,自己也从曾经的应聘者变成了面试者,才终于明白这样的道理:面试官远远要比应聘者狡猾得多。 不按套路出牌是面试官的“基本素养”,多年的工作经验使他们完全不需要提前准备一些特定的题目和答案,随便的几个问题,就可以通过回

m0_56252652的博客 191

qq邮箱发错误:The “From“ header is missing or invalid. Please follow RFC5322, RFC2047, RFC822 standard pro

如果还报错 (550, b’The mail may contain inappropriate words or content.'),可能是你message[‘From’]中的< senderxxx@qq.com >发送邮箱填错了,必须要和self.sender = ’ senderxxx@qq.com '一样。可能是之前qq邮箱发送协议存在漏洞,可隐藏发送者邮箱。现在换了新协议,导致与原来协议规则、编码出现了一些问题。"python自动发送""python自动发送"

云霄IT的博客 3670

OkHttp 5.3升级引发线上偶发崩溃:根因分析与避坑清单

网络通信是移动应用的基石,HTTP/2 多路复用与连接池机制在提升性能的同时,也引入了复杂的运行时行为。底层网络库的版本升级往往隐含行为变更,这些“隐形变更”在弱网、连接复用、大请求头等场景下可能触发偶发崩溃,如 OkHttp 常见的 stream was reset、Connection closed 等异常。本文从 HTTP/2 帧校验、连接池回收策略、URL 容错收紧等维度,剖析 OkHttp 5.3.0 升级后线上故障的根因,并给出请求头瘦身、连接参数调整、重试兜底等工程化解法。针对 SDK 升级特

weixin_30843121的博客 303

图神经网络与大模型融合的理论综述:架构、机制与未来方向

然而,它们普遍缺乏对图结构数据的原生支持,无法直接处理边、节点之间的拓扑关系,这限制了其在关系密集型任务中的表现 [23]。2020年发布的BERT [16] 开启了自监督预训练时代,而2021年后,T5 [17]、PaLM [18]、LLaMA [19] 等模型相继推出,参数规模突破千亿级,展现出惊人的上下文学习(In-context Learning)与链式推理(Chain-of-Thought)能力 [20]。例如,将医学影像作为图节点,结合病理报告文本,实现更精准的疾病诊断 [58]。

andeyeluguo的博客 295

【嵌入式硬件】DRV8874电机驱动

1)N沟道H桥电机驱动;2)驱动1个双向有刷直流电机;3)2个单向有刷直流电机;4)4.5V-37V工作电压范围;5)集成电流感测和调节;6)成比例电流输出(IPROPI);7)可选电流调节(IMODE):逐周期或固定关断时间;8)支持1.8、3V、5V逻辑输入;9)集成保护:欠压、电荷泵欠压、过流保护、输出关闭、热关断、自动故障恢复。

qq_39200110的博客 4424

alpha冲刺9

队名:日不落战队 安琪(队长) 今天完成的任务 协助开发手写涂鸦demo。 okhttp学习第三弹。 明天的计划 协助开发语音存储demo。 还剩下的任务 个人信息数据get。 遇到的困难 困难:整理冲刺阶段成果的时候发现虽然大家都做了不少东西,但因为饼画的太大,以及有些东西现阶段做了也看不出来,导致alpha版本的整体完成度并不高。 解决方案:与队友进行友...

dengzhai1963的博客 132

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Alpha 冲刺 (9/10)

队名:日不落战队 安琪(队长) 今天完成的任务 协助开发手写涂鸦demo。 okhttp学习第三弹。 明天的计划 协助开发语音存储demo。 还剩下的任务 个人信息数据get。 遇到的困难 困难:整理冲刺阶段成果的时候发现虽然大家都做了不少东西,但因为饼画的太大,以及有些东西现阶段做了也看不出来,导致alpha版本的整体完成度并不高。 解决方案:与队友进行友好的协商,...

weixin_30867015的博客 59

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: 真香定律,我就是从这里跳下去也不刷面试题!真香~
下一篇: 都说衣不如新人不如故,技术是学新不学旧的?IPC+view+Handler+线程。
初壹十五a
博客等级 码龄8年 146粉丝 257原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值