聊聊HttpClient的RedirectStrategy
序
本文主要研究一下HttpClient的RedirectStrategy
RedirectStrategy
org/apache/http/client/RedirectStrategy.java
public interface RedirectStrategy {/*** Determines if a request should be redirected to a new location* given the response from the target server.** @param request the executed request* @param response the response received from the target server* @param context the context for the request execution** @return {@code true} if the request should be redirected, {@code false}* otherwise*/boolean isRedirected(HttpRequest request,HttpResponse response,HttpContext context) throws ProtocolException;/*** Determines the redirect location given the response from the target* server and the current request execution context and generates a new* request to be sent to the location.** @param request the executed request* @param response the response received from the target server* @param context the context for the request execution** @return redirected request*/HttpUriRequest getRedirect(HttpRequest request,HttpResponse response,HttpContext context) throws ProtocolException;}
RedirectStrategy接口定义了isRedirected方法用于判断是否需要redirect,还定义了getRedirect方法用于返回redirect的目标地址
DefaultRedirectStrategy
org/apache/http/impl/client/DefaultRedirectStrategy.java
@Contract(threading = ThreadingBehavior.IMMUTABLE)
public class DefaultRedirectStrategy implements RedirectStrategy {private final Log log = LogFactory.getLog(getClass());/*** @deprecated (4.3) use {@link org.apache.http.client.protocol.HttpClientContext#REDIRECT_LOCATIONS}.*/@Deprecatedpublic static final String REDIRECT_LOCATIONS = "http.protocol.redirect-locations";public static final DefaultRedirectStrategy INSTANCE = new DefaultRedirectStrategy();private final String[] redirectMethods;public DefaultRedirectStrategy() {this(new String[] {HttpGet.METHOD_NAME,HttpHead.METHOD_NAME});}/*** Constructs a new instance to redirect the given HTTP methods.** @param redirectMethods The methods to redirect.* @since 4.5.10*/public DefaultRedirectStrategy(final String[] redirectMethods) {super();final String[] tmp = redirectMethods.clone();Arrays.sort(tmp);this.redirectMethods = tmp;}@Overridepublic boolean isRedirected(final HttpRequest request,final HttpResponse response,final HttpContext context) throws ProtocolException {Args.notNull(request, "HTTP request");Args.notNull(response, "HTTP response");final int statusCode = response.getStatusLine().getStatusCode();final String method = request.getRequestLine().getMethod();final Header locationHeader = response.getFirstHeader("location");switch (statusCode) {case HttpStatus.SC_MOVED_TEMPORARILY:return isRedirectable(method) && locationHeader != null;case HttpStatus.SC_MOVED_PERMANENTLY:case HttpStatus.SC_TEMPORARY_REDIRECT:return isRedirectable(method);case HttpStatus.SC_SEE_OTHER:return true;default:return false;} //end of switch}/*** @since 4.2*/protected boolean isRedirectable(final String method) {return Arrays.binarySearch(redirectMethods, method) >= 0;}@Overridepublic HttpUriRequest getRedirect(final HttpRequest request,final HttpResponse response,final HttpContext context) throws ProtocolException {final URI uri = getLocationURI(request, response, context);final String method = request.getRequestLine().getMethod();if (method.equalsIgnoreCase(HttpHead.METHOD_NAME)) {return new HttpHead(uri);} else if (method.equalsIgnoreCase(HttpGet.METHOD_NAME)) {return new HttpGet(uri);} else {final int status = response.getStatusLine().getStatusCode();return status == HttpStatus.SC_TEMPORARY_REDIRECT? RequestBuilder.copy(request).setUri(uri).build(): new HttpGet(uri);}}}
DefaultRedirectStrategy实现了RedirectStrategy接口,它定义了redirectMethods,默认是Get和Head;isRedirected方法先获取response的statusCode,对于302需要location的header有值且请求method在redirectMethods中(
isRedirectable),对于301及307仅仅判断isRedirectable,对于303返回true,其余的返回false
getRedirect方法先通过getLocationURI获取目标地址,然后针对get或者head分别构造HttpHead及HttpGet,剩下的根据statusCode判断,是307则拷贝原来的request,否则返回HttpGet
RedirectExec
org/apache/http/impl/execchain/RedirectExec.java
/*** Request executor in the request execution chain that is responsible* for handling of request redirects.* <p>* Further responsibilities such as communication with the opposite* endpoint is delegated to the next executor in the request execution* chain.* </p>** @since 4.3*/
@Contract(threading = ThreadingBehavior.IMMUTABLE_CONDITIONAL)
public class RedirectExec implements ClientExecChain {private final Log log = LogFactory.getLog(getClass());private final ClientExecChain requestExecutor;private final RedirectStrategy redirectStrategy;private final HttpRoutePlanner routePlanner;public RedirectExec(final ClientExecChain requestExecutor,final HttpRoutePlanner routePlanner,final RedirectStrategy redirectStrategy) {super();Args.notNull(requestExecutor, "HTTP client request executor");Args.notNull(routePlanner, "HTTP route planner");Args.notNull(redirectStrategy, "HTTP redirect strategy");this.requestExecutor = requestExecutor;this.routePlanner = routePlanner;this.redirectStrategy = redirectStrategy;}@Overridepublic CloseableHttpResponse execute(final HttpRoute route,final HttpRequestWrapper request,final HttpClientContext context,final HttpExecutionAware execAware) throws IOException, HttpException {Args.notNull(route, "HTTP route");Args.notNull(request, "HTTP request");Args.notNull(context, "HTTP context");final List<URI> redirectLocations = context.getRedirectLocations();if (redirectLocations != null) {redirectLocations.clear();}final RequestConfig config = context.getRequestConfig();final int maxRedirects = config.getMaxRedirects() > 0 ? config.getMaxRedirects() : 50;HttpRoute currentRoute = route;HttpRequestWrapper currentRequest = request;for (int redirectCount = 0;;) {final CloseableHttpResponse response = requestExecutor.execute(currentRoute, currentRequest, context, execAware);try {if (config.isRedirectsEnabled() &&this.redirectStrategy.isRedirected(currentRequest.getOriginal(), response, context)) {if (redirectCount >= maxRedirects) {throw new RedirectException("Maximum redirects ("+ maxRedirects + ") exceeded");}redirectCount++;final HttpRequest redirect = this.redirectStrategy.getRedirect(currentRequest.getOriginal(), response, context);if (!redirect.headerIterator().hasNext()) {final HttpRequest original = request.getOriginal();redirect.setHeaders(original.getAllHeaders());}currentRequest = HttpRequestWrapper.wrap(redirect);if (currentRequest instanceof HttpEntityEnclosingRequest) {RequestEntityProxy.enhance((HttpEntityEnclosingRequest) currentRequest);}final URI uri = currentRequest.getURI();final HttpHost newTarget = URIUtils.extractHost(uri);if (newTarget == null) {throw new ProtocolException("Redirect URI does not specify a valid host name: " +uri);}// Reset virtual host and auth states if redirecting to another hostif (!currentRoute.getTargetHost().equals(newTarget)) {final AuthState targetAuthState = context.getTargetAuthState();if (targetAuthState != null) {this.log.debug("Resetting target auth state");targetAuthState.reset();}final AuthState proxyAuthState = context.getProxyAuthState();if (proxyAuthState != null && proxyAuthState.isConnectionBased()) {this.log.debug("Resetting proxy auth state");proxyAuthState.reset();}}currentRoute = this.routePlanner.determineRoute(newTarget, currentRequest, context);if (this.log.isDebugEnabled()) {this.log.debug("Redirecting to '" + uri + "' via " + currentRoute);}EntityUtils.consume(response.getEntity());response.close();} else {return response;}} catch (final RuntimeException ex) {response.close();throw ex;} catch (final IOException ex) {response.close();throw ex;} catch (final HttpException ex) {// Protocol exception related to a direct.// The underlying connection may still be salvaged.try {EntityUtils.consume(response.getEntity());} catch (final IOException ioex) {this.log.debug("I/O error while releasing connection", ioex);} finally {response.close();}throw ex;}}}}
RedirectExec实现了ClientExecChain接口,其构造器要求传入requestExecutor、redirectStrategy、routePlanner,其execute方法会先获取maxRedirects参数,然后执行requestExecutor.execute,接着在config.isRedirectsEnabled()以及redirectStrategy.isRedirected为true时才进入redirect逻辑,它会先判断是否超出maxRedirects,大于等于则抛出RedirectException,否则通过redirectStrategy.getRedirect获取HttpRequest,更新currentRoute,然后清理entity关闭response继续下次循环,即执行redirect逻辑。
小结
HttpClient的RedirectStrategy定义了两个方法,一个是是否需要redirect,一个是获取redirect的请求,DefaultRedirectStrategy的构造器支持传入redirectMethods,默认是Get和Head,isRedirected方法主要是对302,301,307,303进行了判断,getRedirect方法主要是通过location获取目标地址,然后根据原来的method和statusCode构造HttpUriRequest。
相关文章:
聊聊HttpClient的RedirectStrategy
序 本文主要研究一下HttpClient的RedirectStrategy RedirectStrategy org/apache/http/client/RedirectStrategy.java public interface RedirectStrategy {/*** Determines if a request should be redirected to a new location* given the response from the target ser…...
【1day】复现宏景OA KhFieldTree接口 SQL注入漏洞
注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、资产测绘 三、漏洞复现 四、漏洞修复 一、漏洞描述 宏景OA是一款基于...
同为科技TOWE智能PDU引领数据中心机房远控用电安全高效
随着数据中心的环境变得更加动态和复杂,许多数据中心都在对数据中心管理人员施加压力,要求提高可用性,同时降低成本,提升效率。新一代高密度服务器和网络设备的投入使用,增加了对更高密度机架的需求,并对整…...
支付成功后给指定人员发送微信公众号消息
支付成功后给指定人员(导购)发送微信公众号消息 微信openid已录入数据库表 调用后台接口发送消息接口调用代码如下: //----add by grj 20231017 start //订单支付成功发送微信公众号消息$.ajax({url:http://www.menggu100.com:7077/strutsJsp…...
漏洞复现--安恒明御安全网关文件上传
免责声明: 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…...
简单的对称加密
异或 异或算法的好处便是数A和数B异或后,把结果再和数A异或便可得到B,或者和数B异或可重新得到数据A。利用异或的这个特性可简单实现数据的加密和解密算法。 恺撒密码 恺撒密码的替换方法是通过排列明文和密文字母表,密文字母表示通过将明…...
vue源码笔记之——响应系统
vue是一种声明式范式编程,使用vue者只需要告诉其想要什么结果,无需关心具体实现(vue内部做了,底层是利用命令式范式) 1. reactive为什么只能操作对象,对于基本数据类型,需要用ref? …...
Android Studio Giraffe | 2022.3.1
Android Gradle 插件和 Android Studio 兼容性 Android Studio 构建系统以 Gradle 为基础,并且 Android Gradle 插件 (AGP) 添加了几项专用于构建 Android 应用的功能。下表列出了各个 Android Studio 版本所需的 AGP 版本。 如果您的项目不受某个特定版本的 Andr…...
Spring Boot 3.0 已经就绪,您准备好了么?
Java 微服务开发框架王者 Spring 2014 年的 4 月,Spring Boot 1.0.0 正式发布。距离 1.0 版本的发布已经过去了 9 年多的时间,如今 Spring Boot 已经被 Java 开发者广泛使用,正如 JRebel 的 2022 年开发者生产力报告中提到的那样,…...
5+非肿瘤分析,分型+WGCNA+机器学习筛选相关基因
今天给同学们分享一篇非肿瘤分型机器学习WGCNA实验的生信文章“Identification of diagnostic markers related to oxidative stress and inflammatory response in diabetic kidney disease by machine learning algorithms: Evidence from human transcriptomic data and mou…...
算法课作业2 OJ for Divide and Conquer
https://vjudge.net/contest/581947 A - Ultra-QuickSort 题意 每次给n个无序的数,互不重复,问最少需要多少次必要的交换操作使n个数有序。 思路 看一眼想到逆序数,然后验证了逆序数的个数符合样例,但想了一个3 2 1的话实际上…...
申请全国400电话的步骤及注意事项
导语:随着企业的发展,越来越多的公司开始意识到全国400电话的重要性。本文将介绍申请全国400电话的步骤及注意事项,帮助企业顺利办理相关手续。 一、了解全国400电话的概念和优势 全国400电话是一种统一的客服热线号码,以“400”…...
C++ 的设计模式之 工厂方法加单例
在下面的示例中,我将演示如何创建一个工厂类,该工厂类能够生成四个不同类型的单例对象,每个单例对象都通过单独的工厂方法进行创建。 #include <iostream> #include <mutex>// Singleton base class class Singleton { protecte…...
Deploy、Service与Ingress
Deployment 自愈 介绍:控制Pod,使Pod拥有多副本,自愈,扩缩容等能力 # 清除所有Pod,比较下面两个命令有何不同效果? kubectl run mynginx --imagenginxkubectl create deployment mytomcat --imagetomcat:8.5.68 # 自…...
定制化推送+精细化运营,Mobpush助力《迷你世界》用户留存率提升23%
随着智能设备的市场下沉,手游市场迎来了爆发式增长,《迷你世界》作为一款于2015年推出的手游,一经问世就饱受欢迎。上线短短三年,迷你世界在应用商店下载量已经高达2亿次,周下载量两千万,稳居第一名&#x…...
深度学习零基础教程
代码运行软件安装: anaconda:一个管理环境的软件–>https://blog.csdn.net/scorn_/article/details/106591160(可选装) pycharm:一个深度学习运行环境–>https://blog.csdn.net/scorn_/article/details/106591160…...
简单测试一下 展锐的 UDX710 性能
最近在接触 联通5G CPE VN007 ,发现使用的是 展锐的Unisoc UDX710 CPU,正好简单的测试一下这颗CPU CPU信息 UDX710 是一颗 双核 ARM Cortex-A55 处理器,主频高达 1.35GHz processor : 0 BogoMIPS : 52.00 Features : fp…...
一百九十、Hive——Hive刷新分区MSCK REPAIR TABLE
一、目的 在用Flume采集Kafka中的数据直接写入Hive的ODS层静态分区表后,需要刷新表,才能导入分区和数据。原因很简单,就是Hive表缺乏分区的元数据 二、实施步骤 (一)问题——在Flume采集Kafka中的数据写入HDFS后&am…...
智慧公厕:探索未来城市环境卫生设施建设新标杆
智慧公厕是当代城市建设的一项重要举措,它集先进技术、人性化设计和智能管理于一体,为人们提供更为舒适、便捷和卫生的厕所环境。现代智慧公厕的功能异常丰富,从厕位监测到多媒体信息交互,从自动化清洁到环境调控,每一…...
高压放大器在无线电能中应用有哪些
高压放大器是一种用于放大电信号的放大器,可以将输入的低电压信号放大到更高的输出电压水平。在无线电通信和其他相关领域中,高压放大器具有广泛的应用。本文将详细介绍高压放大器在无线电能中的应用。 无线电发射:高压放大器在无线电发射中起…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
nnUNet V2修改网络——暴力替换网络为UNet++
更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...
