resttemplate怎么获取header

resttemplate怎么获取header,第1张

定义一个简单的restful接口 @RestController public class TestController { @RequestMapping(value = "testPost", method = RequestMethod.POST) public ResponseBean testPost(@RequestBody RequestBean requestBean) { ResponseBean responseBean = new ResponseBean()responseBean.setRetCode("0000")responseBean.setRetMsg("succ")return responseBean} } 使用RestTemplate访问该服务 //请求地址 String url = ""//入参 RequestBean requestBean = new RequestBean()requestBean.setTest1("1")requestBean.setTest2("2")requestBean.setTest3("3")RestTemplate restTemplate = new RestTemplate()ResponseBean responseBean = restTemplate.postForObject(url, requestBean, ResponseBean.class)从这个例子可以看出,使用restTemplate访问restful接口非常的简单粗暴无脑。(url, requestMap, ResponseBean.class)这三个参数分别代表 请求地址、请求参数、HTTP响应转换被转换成的对象类型。 RestTemplate方法的名称遵循命名约定,第一部分指出正在调用什么HTTP方法,第二部分指示返回的内容。本例中调用了restTemplate.postForObject方法,post指调用了HTTP的post方法,Object指将HTTP响应转换为您选择的对象类型。还有其他很多类似的方法,有兴趣的同学可以参考官方api。 三.手动指定转换器(HttpMessageConverter) 我们知道,调用reseful接口传递的数据内容是json格式的字符串,返回的响应也是json格式的字符串。然而restTemplate.postForObject方法的请求参数RequestBean和返回参数ResponseBean却都是java类。是RestTemplate通过HttpMessageConverter自动帮我们做了转换的 *** 作。 默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。 如StringHttpMessageConverter来处理text/plainMappingJackson2HttpMessageConverter来处理application/jsonMappingJackson2XmlHttpMessageConverter来处理application/xml。 你可以在org.springframework.http.converter包下找到所有spring帮我们实现好的转换器。 如果现有的转换器不能满足你的需求,你还可以实现org.springframework.http.converter.HttpMessageConverter接口自己写一个。详情参考官方api。 选好了HttpMessageConverter后怎么把它注册到我们的RestTemplate中呢。 RestTemplate restTemplate = new RestTemplate()//获取RestTemplate默认配置好的所有转换器 List<HttpMessageConverter<?>>messageConverters = restTemplate.getMessageConverters()//默认的MappingJackson2HttpMessageConverter在第7个 先把它移除掉 messageConverters.remove(6)//添加上GSON的转换器 messageConverters.add(6, new GsonHttpMessageConverter())这个简单的例子展示了如何使用GsonHttpMessageConverter替换掉默认用来处理application/json的MappingJackson2HttpMessageConverter。 四.设置底层连接方式 要创建一个RestTemplate的实例,您可以像上述例子中简单地调用默认的无参数构造函数。这将使用java.NET包中的标准Java类作为底层实现来创建HTTP请求。 但很多时候我们需要像传统的HttpClient那样设置HTTP请求的一些属性。RestTemplate使用了一种很偷懒的方式实现了这个需求,那就是直接使用一个HttpClient作为底层实现...... //生成一个设置了连接超时时间、请求超时时间、异常最大重试次数的httpClient RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(10000).setSocketTimeout(30000).build()HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(config).setRetryHandler(new DefaultHttpRequestRetryHandler(5, false))HttpClient httpClient = builder.build()//使用httpClient创建一个ClientHttpRequestFactory的实现 ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient)//ClientHttpRequestFactory作为参数构造一个使用作为底层的RestTemplate RestTemplate restTemplate = new RestTemplate(requestFactory)五.设置拦截器(ClientHttpRequestInterceptor) 有时候我们需要对请求做一些通用的拦截设置,这就可以使用拦截器进行处理。拦截器需要我们实现org.springframework.http.client.ClientHttpRequestInterceptor接口自己写。 举个简单的例子,写一个在header中根据请求内容和地址添加令牌的拦截器。 public class TokenInterceptor implements ClientHttpRequestInterceptor { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { //请求地址 String checkTokenUrl = request.getURI().getPath()//token有效时间 int ttTime = (int) (System.currentTimeMillis() / 1000 + 1800)//请求方法名 POST、GET等 String methodName = request.getMethod().name()//请求内容 String requestBody = new String(body)//生成令牌 此处调用一个自己写的方法,有兴趣的朋友可以自行google如何使用ak/sk生成token,此方法跟本教程无关,就不贴出来了 String token = TokenHelper.generateToken(checkTokenUrl, ttTime, methodName, requestBody)//将令牌放入请求header中 request.getHeaders().add("X-Auth-Token",token)return execution.execute(request, body)} } 创建RestTemplate实例的时候可以这样向其中添加拦截器 RestTemplate restTemplate = new RestTemplate()//向restTemplate中添加自定义的拦截器 restTemplate.getInterceptors().add(new TokenInterceptor())

在Spring cloud 框架中,我们都知道,起一个MVC的服务非常简单。 通过controller 注释就可以写一个API的接口了。

但是如果我们的service 想要发起一个新的调用如何做呢?在Spring cloud 下有不少这样的需求。

主要有这么几种方式:

简单介绍下背景, RestTemplate 是一个轻量级的 HTTP的Client ,相对于 Feign 而言。 RestTemplate 有丰富的接口,支持用户对HTTP的各种请求方法和参数的封装 。

OpenFeign 是有 Feign 开发而来。是 Spring Cloud 的子项目之一,在微服务调用中, OpenFeign 非常的得心应手,而且 OpenFeign 还支持各种 HTTP 调用封装,同时还可以整合服务注册( Eureka )、负载均衡、服务治理(熔断、限流、重试)的组件,灵活性提升很多而且实现起来比较简单。

RestTemplate 支持HTTP的 HEAD, GET, POST, PUT, DELETE, OPTIONS、PATCH等大部分方法,还有两个TRACE、CONECT 用的比较少,不支持(查询官方接口确认)。

我们就来总结一下常用的方法的实现。

支持的方法有:

client 的配置,发起一个get请求,把获取的数据 用String 格式化。

server 端的API的是这样式的

Client 如下配置

client的封装如下

服务器端例子,构造一个返回的请求类型

客户端解析例子

DELETE有三个方法的重载。

这三个重载方法,传入的变量不一样,支持 MAP 类型 参数与URL ,支持 Object对象多值传入 , 支持 URL 。都无返回值。

用法就像controller 的API 一样,可以对HTTPserver发起请求

首先,需要在启动类里加上注释

可以通过这么几个HTTP client 组件来封装。例如:

用aop 拦截所有controller 的请求 生成全局traceId

@Pointcut("execution(* *.*.controller..*.*(..))")

public void cutOffPoint() {

}

@Before("cutOffPoint()")

public void doBefore(JoinPoint joinPoint)throws Throwable {

 MDC.put("traceId", "生成全局traceid") 

}

在logback.xml中配置 

<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">

    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %X{TRACEID}- %msg%n

</appender>

到此可以满足大部分的需求

需要注意的部分就是如果用到线程池需要特殊处理

可以参考

https://blog.csdn.net/yangcheng33/article/details/80796129

下面说下我的实现 

项目中主要使用ThreadPoolTaskExecutor因此对他进行改造

复制public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport

implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {

//内容为ThreadPoolTaskExecutor  类中的内容 我这里从新写了一下几个方法

initializeExecutor 方法中  super.execute(new MDCRunnable(decorated))

submitListenable方法中 

ListenableFutureTask future =new ListenableFutureTask<>(new MDCCallable<>(task))

//住所有执行的方法都要改为MDCRunnable MDCCallable

}

MDCRunnable类 为

public class MDCRunnable implements Runnable {

private final Runnable runnable

    private transient final Map_cm = MDC.getCopyOfContextMap()

    public MDCRunnable(Runnable runnable) {

        this.runnable = runnable

    }

@Override

    public void run() {

if (_cm !=null) {

             MDC.setContextMap(_cm)

        }

try {

runnable.run()

        }finally {

MDC.clear()

        }}}

public class MDCCallable implements Callable {

private final Callablecallable

    private transient final Map_cm = MDC.getCopyOfContextMap()

    public MDCCallable(Callable callable) {

this.callable = callable

    }

@Override

    public V call()throws Exception {

if (_cm !=null) {

MDC.setContextMap(_cm)

        }

try {

return callable.call()

        }finally {

MDC.clear()

        }}}

至此我们项目中就完美解决了traceId在本项目中传递

如果是在微服务中传递则 我们微服务之间的调用使用的restTemplate

所有增加一个拦截器

@Configuration

public class RestTemplateConfiguration {

@Bean

@LoadBalanced

    public RestTemplateloadbalancedRestTemplate() {

SimpleClientHttpRequestFactory requestFactory =new SimpleClientHttpRequestFactory()

        // 超时时间,单位毫秒

        requestFactory.setConnectTimeout(3 *1000)

        requestFactory.setReadTimeout(3 *60 *1000)

        RestTemplate restTemplate =new RestTemplate(requestFactory)

        restTemplate.getInterceptors().add(new TraceIdInterceptor())

        return restTemplate

    }

public class TraceIdInterceptorimplements ClientHttpRequestInterceptor {

@Override

    public ClientHttpResponseintercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)throws IOException {

HttpHeaders headers = request.getHeaders()

        traceId= MDC.get("traceId")

        if(StringUtils.isNotBlank(traceId)){

headers.add("traceId",traceId)

        }

return execution.execute(request,body)

    }}}

然后在下游服务器写一个拦截器就可在request head中可以获取traceidl 

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()

String traceId = request.getHeader("traceId")

至此就完成了所有的traceid 本项目 线程 项目之间 都可以用了


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11267038.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-14
下一篇2023-05-14

发表评论

登录后才能评论

评论列表(0条)

    保存