在邮件标头中找到无效的字符_在实践中重试HTTP标头

在邮件标头中找到无效的字符

Retry-After是鲜为人知的HTTP响应标头。 让我引用RFC 2616(HTTP 1.1规范)的相关部分:

14.37重试后

Retry-After响应标头字段可与503服务不可用 )响应一起使用,以指示请求客户端不希望使用服务多长时间。 该字段也可以与任何3xx(重定向)响应一起使用,以指示在发出重定向请求之前,要求用户代理等待的最短时间。 该字段的值可以是响应日期之后的HTTP日期或整数秒(十进制)。

Retry-After  = "Retry-After" ":" ( HTTP-date | delta-seconds )

其用法的两个示例是:

Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Retry-After: 120

在后一个示例中,延迟为2分钟。

尽管具有3xx响应的用例很有趣,尤其是在最终一致的系统中(“ 您的资源将在2秒内在此链接下可用 ),但我们将集中于错误处理。 通过将Retry-After添加到响应服务器,服务器可以在客户端再次可用时向其提供提示。 有人可能会争辩说,服务器几乎不知道何时将其重新联机,但是有几种有效的用例可以通过某种方式推断出这些知识:

  • 计划的维护–这很明显,如果您的服务器在计划的维护窗口内停机,则可以从代理发送Retry-After ,并提供准确的回叫时间。 如果客户理解并尊重此标头,客户当然不会更早地重试
  • 队列/线程池已满-如果您的请求必须由线程池处理且已满,则可以估计何时可以处理下一个请求。 这需要绑定队列(请参阅: ExecutorService – 10个技巧和窍门 ,第6点),并粗略估计处理一项任务需要多长时间。 有了这些知识,您就可以估计何时可以在不排队的情况下为下一个客户提供服务。
  • 断路器断开–在Hystrix中,您可以查询
  • 下一个可用令牌/资源/任何内容

让我们集中讨论一个非平凡的用例。 假设您的Web服务由Hystrix命令支持:

private static final HystrixCommand.Setter CMD_KEY = HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("REST")).andCommandKey(HystrixCommandKey.Factory.asKey("fetch"));@RequestMapping(value = "/", method = GET)
public String fetch() {return fetchCommand().execute();
}private HystrixCommand<String> fetchCommand() {return new HystrixCommand<String>(CMD_KEY) {@Overrideprotected String run() throws Exception {//...}};
}

这可以按预期工作,如果命令失败,超时或断路器断开,客户端将收到503。但是,在断路器的情况下,我们至少可以估计电路再次闭合需要多长时间。 不幸的是,没有公共API可以告诉您在发生灾难性故障时确切的电路将保持断开状态多长时间。 但是我们知道默认情况下断路器保持断开状态多长时间,这是一个很好的最大估计值。 当然,如果基础命令不断失败,电路可能会保持断开状态。 但是Retry-After不能保证服务器会在给定的时间运行,这只是客户端停止尝试的提示。 以下实现很简单,但是很糟糕:

@RequestMapping(value = "/", method = GET)
public ResponseEntity<String> fetch() {final HystrixCommand<String> command = fetchCommand();if (command.isCircuitBreakerOpen()) {return handleOpenCircuit(command);}return new ResponseEntity<>(command.execute(), HttpStatus.OK);
}private ResponseEntity<String> handleOpenCircuit(HystrixCommand<String> command) {final HttpHeaders headers = new HttpHeaders();final Integer retryAfterMillis = command.getProperties().circuitBreakerSleepWindowInMilliseconds().get();headers.set(HttpHeaders.RETRY_AFTER, Integer.toString(retryAfterMillis / 1000));return new ResponseEntity<>(headers, HttpStatus.SERVICE_UNAVAILABLE);
}

如您所见,我们可以询问任何命令其断路器是否断开。 如果打开,则使用circuitBreakerSleepWindowInMilliseconds值设置Retry-After标头。 该解决方案存在一个微妙但灾难性的错误:如果某一天电路断开,我们将再也不会运行命令,因为我们会急于返回503。这意味着Hystrix将永远不会重试执行它,并且电路将永远保持断开状态。 我们必须尝试每次调用命令并捕获适当的异常:

@RequestMapping(value = "/", method = GET)
public ResponseEntity<String> fetch() {final HystrixCommand<String> command = fetchCommand();try {return new ResponseEntity<>(command.execute(), OK);} catch (HystrixRuntimeException e) {log.warn("Error", e);return handleHystrixException(command);}
}private ResponseEntity<String> handleHystrixException(HystrixCommand<String> command) {final HttpHeaders headers = new HttpHeaders();if (command.isCircuitBreakerOpen()) {final Integer retryAfterMillis = command.getProperties().circuitBreakerSleepWindowInMilliseconds().get();headers.set(HttpHeaders.RETRY_AFTER, Integer.toString(retryAfterMillis / 1000));}return new ResponseEntity<>(headers, SERVICE_UNAVAILABLE);
}

这个很好用。 如果命令抛出异常并且相关电路断开,我们将设置适当的标题。 在所有示例中,我们花费毫秒并归一化为秒。 我不建议这样做,但是如果由于某些原因,您在Retry-After标头中选择绝对日期而不是相对超时,则HTTP日期格式最终成为Java的一部分(自JDK 8起):

import java.time.format.DateTimeFormatter;//...final ZonedDateTime after5seconds = ZonedDateTime.now().plusSeconds(5);
final String httpDate = DateTimeFormatter.RFC_1123_DATE_TIME.format(after5seconds);

关于自动DDoS的注意事项

如果将相同的时间戳发送给许多唯一的客户端,则必须谨慎使用Retry-After标头。 想象现在是15:30,然后您将Retry-After: Thu, 10 Feb 2015 15:40:00 GMT发送给周围的所有人-只是因为您以某种方式估计服务将在15:40开通。 您持续发送相同时间戳的时间越长,尊重Retry-After客户端所期望的DDoS“攻击”就越大。 基本上,每个人都将精确安排在15:40重试(显然,时钟未完全对齐,并且网络延迟有所变化,但仍然存在),从而使系统充满了请求。 如果您的系统设计正确,那么您可能会幸免于难。 但是,您可能会通过发送另一个固定的Retry-After报头来减轻这种“攻击”,本质上是Retry-After重新安排攻击。

话虽这么说,避免将固定的绝对时间戳发送给多个唯一的客户端。 即使您确切知道系统何时可用,也可以Retry-After一段时间内分散“ Retry-After值。 实际上,您应该逐渐让越来越多的客户进入,因此请尝试不同的概率分布。

摘要

Retry-After HTTP响应标头既不是普遍已知的,也不是经常适用的。 但是在极少数情况下可以预期停机的情况下,请考虑在服务器端实施停机。 如果客户也意识到这一点,则可以在减少系统流量的同时提高系统吞吐量和响应时间。

翻译自: https://www.javacodegeeks.com/2015/02/retry-http-header-practice.html

在邮件标头中找到无效的字符

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

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

相关文章

C 常见的面试知识点(上)

const 作用1&#xff0c;修饰变量&#xff0c;说明该变量不可以被改变2&#xff0c;修饰指针&#xff0c;分为指向常量的指针&#xff08;pointer to const&#xff09;和自身是常量的指针&#xff08;常量指针&#xff0c;const pointer&#xff09;3&#xff0c;修饰引用&…

brew下载的mysql卸载_Mac中mongoDB的安装与卸载步骤详解

前言MongoDB 是一个基于分布式文件存储的数据库&#xff0c;旨在为 web 应用提供可扩展的高性能数据存储解决方案。本文主要介绍的是关于在mac中安装卸载mongoDB数据库的方法&#xff0c;更多关于mongoDB的使用大家可以参考这篇文章&#xff1a;https://www.jb51.net/article/7…

java 指令重拍_我发现我的Java重拍了!

java 指令重拍在一月份&#xff0c;我写了一篇文章&#xff0c;介绍了一些我希望在Java语言中看到的变化&#xff0c;这些变化会让我更加喜欢它&#xff08;并使它变得更现代&#xff09;。 很多人建议使用许多JVM语言&#xff0c;但我很大程度上不予理会&#xff0c;因为这不是…

java post webservice_[java.webservice] 如何通过HttpPost从服务器上获得一个sessionid

javas Web Service is different from HttpPost, HttpGet and HttpResponse that kind of things. It is more easy to pass anything, any Object you like.如果要利用Web Service返回一个sessionid的话&#xff0c;可以使用从Server返回返回值的形式&#xff0c;也可以在Clie…

C 常见的面试知识点(下)

inline 内联函数的特征相当于把内联函数里面的内容写在调用内联函数处&#xff1b;相当于不用执行进入函数的步骤&#xff0c;直接执行函数体&#xff1b;相当于宏&#xff0c;却比宏多了类型检查&#xff0c;真正具有函数特性&#xff1b;编译器一般不内联包含循环、递归、swi…

php cdi_集成CDI和WebSockets

php cdi考虑尝试一个简单的Java EE 7原型应用程序&#xff0c;该应用程序涉及JAX-RS&#xff08;REST&#xff09;&#xff0c;WebSockets和CDI。 注意 &#xff1a;不想让它成为破坏者-但本文主要讨论我在尝试使用Web套接字和使用CDI作为“胶水”&#xff08;在Java EE应用程…

c语言排序方法有哪几种?

c语言排序方法有&#xff1a;1、简单选择排序&#xff0c;基于O&#xff08;n2&#xff09;时间复杂度的排序算法&#xff1b;2、冒泡排序&#xff1b;3、简单插入排序&#xff1b;4、希尔排序&#xff1b;5、归并排序&#xff0c;基于归并操作的一种排序算法&#xff1b;6、快…

java 类型不可视_jvm高级特性(5)(1)(原子性,可见性,有序性,volatile,概述)

简介&#xff1a;阿姆达尔定律(Amdahl)&#xff1a;该定律通过系统中并行化与串行化的比重来描述多处理器系统能获得的运算加速能力。摩尔定律(Moore)&#xff1a;该定律用于描述处理器晶体管数量与运行效率间的发展关系。当价格不变时&#xff0c;集成电路上可容纳的元器件的数…

工程模式和抽象工厂模式_功能工厂模式

工程模式和抽象工厂模式您是否需要一种非常快速的方法来制作Factory对象&#xff1f; 然后&#xff0c;您需要lambda或其他函数传递&#xff01; 它不仅快速&#xff0c;而且非常简单。 我敢打赌&#xff0c;如果您对Lambdas相当满意&#xff0c;那么您只需阅读标题就可以做到这…

c语言怎么输入3个数输出最大值

方法&#xff1a;首先使用scanf()接收从键盘输入的三个数&#xff1b;然后使用“if else”语句比较三个数的大小&#xff0c;获得最大值&#xff1b;最后使用print()函数将最大值输出即可。c语言输入3个数输出最大值#include int main() { // 输入abc输出最大值 int a; …

java调用ecdh_椭圆曲线ECC ECDH原理 javacard实现

椭圆曲线原理&#xff1a;椭圆曲线的图像并不是椭圆形&#xff0c;椭圆曲线源自于求椭圆弧长的椭圆积分的反函数。定义&#xff1a;椭圆曲线可用下列方程来表示&#xff0c;其中a,b,c,d为系数。E&#xff1a; y2 ax3 bx2 cx d椭圆曲线运算&#xff1a;(相当于交换群)AB&#x…

C 常用新特性(上)

下面是正文&#xff1a;auto类型推导auto可以让编译器在编译器就推导出变量的类型&#xff0c;看代码&#xff1a;利用auto可以通过右边的类型推导出变量的类型。什么时候使用auto呢&#xff1f;简单类型其实没必要使用auto&#xff0c;然而某些复杂类型就有必要使用auto&#…

等级保护测评工作重点难点_重点保护

等级保护测评工作重点难点在“ Java的一些句子 ”一文中&#xff0c;我写道&#xff1a; “受保护的方法和字段可以在同一包中的类中使用&#xff08;到目前为止与私有包相同&#xff09;&#xff0c;此外&#xff0c;还可以从其他类中使用受保护的方法和字段&#xff0c;这些类…

c编译程序是什么?

c编译程序是由计算机厂家提供的一套软件。c编译程序又称c语言编译器&#xff0c;是指用c语言书写的源程序&#xff0c;翻译成等价的机器语言格式目标程序的翻译程序。编译程序属于采用生成性实现途径实现的翻译程序。它以高级程序设计语言书写的源程序作为输入&#xff0c;而以…

运动基元_基元需要走吗?

运动基元我目前正在使用JSF作为视图技术&#xff0c;使用JPA作为持久层的企业应用程序。 它可能是支持bean或服务方法中的某种东西&#xff0c;但令我震惊&#xff1a;是否有充分的理由在企业应用程序中使用原语&#xff1f; 当我开始围绕J2SE 1.2&#xff08;或者是J2SE 5.0&…

mysql 三种工作模式_mybatis三种批量插入方式对比【面试+工作】

准备&#xff1a;1.表结构CREATE TABLE t_user (id varchar(32) CHARACTER SET utf8 NOT NULL COMMENT 主键,name varchar(50) CHARACTER SET utf8 DEFAULT NULL COMMENT 用户名,del_flag char(1) CHARACTER SET utf8 DEFAULT NULL COMMENT 删除标示,PRIMARY KEY (id)) ENGINEI…

C 常用新特性(下)

多线程什么是多线程这里就不过多介绍&#xff0c;新特性关于多线程最主要的就是std::thread的使用&#xff0c;它的使用也很简单&#xff0c;看代码&#xff1a;这里记住&#xff0c;std::thread在其对象生命周期结束时必须要调用join()或者detach()&#xff0c;否则程序会term…

ant 路径_在Ant中显示路径

ant 路径在博客文章Java and Ant Properties Refresher和Ant <echoproperties /> Task中 &#xff0c;我写了一篇关于如何了解Ant构建如何看到属性的文章&#xff0c;这有助于更好地理解该构建。 通常情况下&#xff0c;在构建过程中看到构建中使用的各种路径也很有价值&…

java8默认垃圾回收器,Java 8的默认垃圾收集器

What is the default garbage collector for Java 8?When I check the JMX Beans, they reveal it to be the parallel collector for the new generation and the old serial collector for the old generation.解决方案Selecting the default garbage collector (among othe…

c语言中结束本次循环的语句是什么

c语言中结束本次循环的语句是“continue”。控制语句continue只能作用于循环体中&#xff0c;其作用是结束本次循环&#xff0c;跳到判断循环的位置&#xff0c;即重新开始下一次循环。在C语言中&#xff0c;控制语句“continue”用于循环体中结束本次循环&#xff0c;重新开始…