当前位置: 首页 > news >正文

聊聊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引领数据中心机房远控用电安全高效

随着数据中心的环境变得更加动态和复杂&#xff0c;许多数据中心都在对数据中心管理人员施加压力&#xff0c;要求提高可用性&#xff0c;同时降低成本&#xff0c;提升效率。新一代高密度服务器和网络设备的投入使用&#xff0c;增加了对更高密度机架的需求&#xff0c;并对整…...

支付成功后给指定人员发送微信公众号消息

支付成功后给指定人员&#xff08;导购&#xff09;发送微信公众号消息 微信openid已录入数据库表 调用后台接口发送消息接口调用代码如下&#xff1a; //----add by grj 20231017 start //订单支付成功发送微信公众号消息$.ajax({url:http://www.menggu100.com:7077/strutsJsp…...

漏洞复现--安恒明御安全网关文件上传

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…...

简单的对称加密

异或 异或算法的好处便是数A和数B异或后&#xff0c;把结果再和数A异或便可得到B&#xff0c;或者和数B异或可重新得到数据A。利用异或的这个特性可简单实现数据的加密和解密算法。 恺撒密码 恺撒密码的替换方法是通过排列明文和密文字母表&#xff0c;密文字母表示通过将明…...

vue源码笔记之——响应系统

vue是一种声明式范式编程&#xff0c;使用vue者只需要告诉其想要什么结果&#xff0c;无需关心具体实现&#xff08;vue内部做了&#xff0c;底层是利用命令式范式&#xff09; 1. reactive为什么只能操作对象&#xff0c;对于基本数据类型&#xff0c;需要用ref&#xff1f; …...

Android Studio Giraffe | 2022.3.1

Android Gradle 插件和 Android Studio 兼容性 Android Studio 构建系统以 Gradle 为基础&#xff0c;并且 Android Gradle 插件 (AGP) 添加了几项专用于构建 Android 应用的功能。下表列出了各个 Android Studio 版本所需的 AGP 版本。 如果您的项目不受某个特定版本的 Andr…...

Spring Boot 3.0 已经就绪,您准备好了么?

Java 微服务开发框架王者 Spring 2014 年的 4 月&#xff0c;Spring Boot 1.0.0 正式发布。距离 1.0 版本的发布已经过去了 9 年多的时间&#xff0c;如今 Spring Boot 已经被 Java 开发者广泛使用&#xff0c;正如 JRebel 的 2022 年开发者生产力报告中提到的那样&#xff0c…...

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个无序的数&#xff0c;互不重复&#xff0c;问最少需要多少次必要的交换操作使n个数有序。 思路 看一眼想到逆序数&#xff0c;然后验证了逆序数的个数符合样例&#xff0c;但想了一个3 2 1的话实际上…...

申请全国400电话的步骤及注意事项

导语&#xff1a;随着企业的发展&#xff0c;越来越多的公司开始意识到全国400电话的重要性。本文将介绍申请全国400电话的步骤及注意事项&#xff0c;帮助企业顺利办理相关手续。 一、了解全国400电话的概念和优势 全国400电话是一种统一的客服热线号码&#xff0c;以“400”…...

C++ 的设计模式之 工厂方法加单例

在下面的示例中&#xff0c;我将演示如何创建一个工厂类&#xff0c;该工厂类能够生成四个不同类型的单例对象&#xff0c;每个单例对象都通过单独的工厂方法进行创建。 #include <iostream> #include <mutex>// Singleton base class class Singleton { protecte…...

Deploy、Service与Ingress

Deployment 自愈 介绍:控制Pod&#xff0c;使Pod拥有多副本&#xff0c;自愈&#xff0c;扩缩容等能力 # 清除所有Pod&#xff0c;比较下面两个命令有何不同效果&#xff1f; kubectl run mynginx --imagenginxkubectl create deployment mytomcat --imagetomcat:8.5.68 # 自…...

定制化推送+精细化运营,Mobpush助力《迷你世界》用户留存率提升23%

随着智能设备的市场下沉&#xff0c;手游市场迎来了爆发式增长&#xff0c;《迷你世界》作为一款于2015年推出的手游&#xff0c;一经问世就饱受欢迎。上线短短三年&#xff0c;迷你世界在应用商店下载量已经高达2亿次&#xff0c;周下载量两千万&#xff0c;稳居第一名&#x…...

深度学习零基础教程

代码运行软件安装&#xff1a; anaconda:一个管理环境的软件–>https://blog.csdn.net/scorn_/article/details/106591160&#xff08;可选装&#xff09; pycharm&#xff1a;一个深度学习运行环境–>https://blog.csdn.net/scorn_/article/details/106591160&#xf…...

简单测试一下 展锐的 UDX710 性能

最近在接触 联通5G CPE VN007 &#xff0c;发现使用的是 展锐的Unisoc UDX710 CPU&#xff0c;正好简单的测试一下这颗CPU CPU信息 UDX710 是一颗 双核 ARM Cortex-A55 处理器&#xff0c;主频高达 1.35GHz processor : 0 BogoMIPS : 52.00 Features : fp…...

一百九十、Hive——Hive刷新分区MSCK REPAIR TABLE

一、目的 在用Flume采集Kafka中的数据直接写入Hive的ODS层静态分区表后&#xff0c;需要刷新表&#xff0c;才能导入分区和数据。原因很简单&#xff0c;就是Hive表缺乏分区的元数据 二、实施步骤 &#xff08;一&#xff09;问题——在Flume采集Kafka中的数据写入HDFS后&am…...

智慧公厕:探索未来城市环境卫生设施建设新标杆

智慧公厕是当代城市建设的一项重要举措&#xff0c;它集先进技术、人性化设计和智能管理于一体&#xff0c;为人们提供更为舒适、便捷和卫生的厕所环境。现代智慧公厕的功能异常丰富&#xff0c;从厕位监测到多媒体信息交互&#xff0c;从自动化清洁到环境调控&#xff0c;每一…...

高压放大器在无线电能中应用有哪些

高压放大器是一种用于放大电信号的放大器&#xff0c;可以将输入的低电压信号放大到更高的输出电压水平。在无线电通信和其他相关领域中&#xff0c;高压放大器具有广泛的应用。本文将详细介绍高压放大器在无线电能中的应用。 无线电发射&#xff1a;高压放大器在无线电发射中起…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...