您现在的位置是:主页 > news > vue 大型网站开发/想做网站找什么公司
vue 大型网站开发/想做网站找什么公司
admin2025/5/19 3:01:40【news】
简介vue 大型网站开发,想做网站找什么公司,成都建站网站模板,酒店网站 asp.net微服务已不再是趋势。 不管喜欢与否,他们会留下来。 但是,在接受微服务架构并正确实施它们之前,仍存在巨大差距。 提醒一下,人们可能首先想检查一下分布式计算的许多谬误 。 克服这些要求所必需的所有要求中,包括能够跟…
微服务已不再是趋势。 不管喜欢与否,他们会留下来。 但是,在接受微服务架构并正确实施它们之前,仍存在巨大差距。 提醒一下,人们可能首先想检查一下分布式计算的许多谬误 。 克服这些要求所必需的所有要求中,包括能够跟随特定业务场景中涉及的微服务遵循一个HTTP请求的能力-用于监视和调试。
它的一种可能的实现是专用的HTTP标头,该标头具有不变的值,该值沿调用链中涉及的每个微服务传递。 这周,我在Spring微服务上开发了这种排序监控,并希望分享实现方法。
标头即用转发
在Spring生态系统中, Spring Cloud Sleuth是专用于此 的库:
Spring Cloud Sleuth从Dapper , Zipkin和HTrace大量借鉴了Spring Cloud的分布式跟踪解决方案。 对于大多数用户而言,Sleuth应该是不可见的,并且您与外部系统的所有交互都应自动进行检测。 您可以简单地在日志中捕获数据,也可以将其发送到远程收集器服务。
在Spring Boot项目中,将Spring Cloud Sleuth库添加到类路径将自动为所有调用添加2个HTTP标头:
由单个事务的所有HTTP调用共享, 即希望的事务标识符
识别交易期间单个微服务的工作
X-B3-Traceid
X-B3-Spanid
Spring Cloud Sleuth提供了一些自定义功能,例如备用标头名称,但需要付出一些额外的代码。
不同于开箱即用的功能
从整洁的架构开始时,这些功能非常方便。 不幸的是,我正在工作的项目具有不同的上下文:
- 交易ID不是由调用链中的第一个微服务创建的-强制外观代理会创建
- 交易ID不是数字-并且Sleuth仅处理数字值
- 需要另一个标头。 其目标是将与不同呼叫链上的一个业务场景相关的所有请求分组
- 第三个标头是必需的。 调用链中的每个新微服务都会增加它
解决方案架构师的第一步是检查API管理产品(例如Apigee(最近由Google购买))并搜索提供符合这些要求的功能的产品。 不幸的是,当前上下文不允许这样做。
编写要求
最后,我最终使用Spring框架编写了以下代码:
- 从初始请求中读取和存储标题
- 将它们写入新的微服务请求中
- 从微服务响应中读取和存储标头
- 将它们写入对发起方的最终响应中,不要忘记增加调用计数器
标头持有人
第一步是创建负责保存所有必要标头的实体。 它被想象为HeadersHolder
。 怪我所有你想要的,我找不到一个更具描述性的名字。
privateconstvalHOP_KEY="hop"
privateconstvalREQUEST_ID_KEY="request-id"
privateconstvalSESSION_ID_KEY="session-id"data classHeadersHolder(varhop:Int?,varrequestId:String?,varsessionId:String?)
有趣的部分是确定哪个范围与该类的实例更相关。显然,必须有多个实例,因此这使singleton
不适合。 同样,由于数据必须存储在多个请求中,因此不能将其prototype
。 最后,管理实例的唯一可能方法是通过ThreadLocal
。
尽管可以管理ThreadLocal
,但让我们利用Spring的功能,因为它可以轻松添加新的作用域。 ThreadLocal
已经有一个现成的作用域,只需要在上下文中注册它即可。 这将直接转换为以下代码:
internalconstvalTHREAD_SCOPE="thread"@Scope(THREAD_SCOPE)
annotationclassThreadScope@Configuration
openclassWebConfigurer{@Bean@ThreadScopeopenfunheadersHolder()=HeadersHolder()@BeanopenfuncustomScopeConfigurer()=CustomScopeConfigurer().apply{addScope(THREAD_SCOPE,SimpleThreadScope())}
}
服务器部分中的标题
让我们实现上面的要求1和4:从请求中读取标头,并将其写入响应。 同样,在请求-响应周期之后,还需要重置标头以准备下一个。
这也要求将持有人类别更新为对OOP更友好:
data classHeadersHolderprivateconstructor(privatevarhop:Int?,privatevarrequestId:String?,privatevarsessionId:String?){constructor():this(null,null,null)funreadFrom(request:HttpServletRequest){this.hop=request.getIntHeader(HOP_KEY)this.requestId=request.getHeader(REQUEST_ID_KEY)this.sessionId=request.getHeader(SESSION_ID_KEY)}funwriteTo(response:HttpServletResponse){hop?.let{response.addIntHeader(HOP_KEY,hopasInt)}response.addHeader(REQUEST_ID_KEY,requestId)response.addHeader(SESSION_ID_KEY,sessionId)}funclear(){hop=nullrequestId=nullsessionId=null}
}
为了使控制器不受头管理的关注,相关代码应位于过滤器或类似组件中。 在Spring MVC生态系统中,这转化为拦截器。
abstractclassHeadersServerInterceptor:HandlerInterceptorAdapter(){abstractvalheadersHolder:HeadersHolderoverridefunpreHandle(request:HttpServletRequest,response:HttpServletResponse,handler:Any):Boolean{headersHolder.readFrom(request)returntrue}overridefunafterCompletion(request:HttpServletRequest,response:HttpServletResponse,handler:Any,ex:Exception?){with(headersHolder){writeTo(response)clear()}}
}@ConfigurationopenclassWebConfigurer:WebMvcConfigurerAdapter(){overridefunaddInterceptors(registry:InterceptorRegistry){registry.addInterceptor(object: HeadersServerInterceptor(){overridevalheadersHolder:HeadersHolderget()=headersHolder()})}
}
请注意调用clear()
方法以重置下一个请求的标头持有者。
最重要的是抽象的 headersHolder
属性。 由于其作用域-线程小于适配器的作用域,因此不能直接注入它,而只能在Spring上下文启动期间注入它。 因此,Spring提供了查找方法注入 。 上面的代码是其在Kotlin中的直接翻译。
客户电话中的标题
前面的代码假定当前的微服务位于调用者链的末尾:它读取请求标头并将其写回响应中(不要忘记增加“跳数”计数器)。 但是,监视仅与具有多个单个链接的呼叫者链相关。 如何将标头传递给下一个微服务(并将其返回)-上面的要求2和3?
Spring提供了一个方便的抽象来处理该客户端部分ClientHttpRequestInterceptor
,可以将其注册到REST模板。 关于范围不匹配,使用与上面的拦截器处理程序相同的注入技巧。
abstractclassHeadersClientInterceptor:ClientHttpRequestInterceptor{abstractvalheadersHolder:HeadersHolderoverridefunintercept(request:HttpRequest,body:ByteArray,execution:ClientHttpRequestExecution):ClientHttpResponse{with(headersHolder){writeTo(request.headers)returnexecution.execute(request,body).apply{readFrom(this.headers)}}}
}@Configuration
openclassWebConfigurer:WebMvcConfigurerAdapter(){@BeanopenfunheadersClientInterceptor()=object: HeadersClientInterceptor(){overridevalheadersHolder:HeadersHolderget()=headersHolder()}@BeanopenfunoAuth2RestTemplate()=OAuth2RestTemplate(clientCredentialsResourceDetails()).apply{interceptors=listOf(headersClientInterceptor())}
}
使用此代码,每个使用oAuth2RestTemplate()
REST调用都将具有由拦截器自动管理的标头。
HeadersHolder
只需要快速更新:
data classHeadersHolderprivateconstructor(privatevarhop:Int?,privatevarrequestId:String?,privatevarsessionId:String?){funreadFrom(headers:org.springframework.http.HttpHeaders){headers[HOP_KEY]?.let{it.getOrNull(0)?.let{this.hop=it.toInt()}}headers[REQUEST_ID_KEY]?.let{this.requestId=it.getOrNull(0)}headers[SESSION_ID_KEY]?.let{this.sessionId=it.getOrNull(0)}}funwriteTo(headers:org.springframework.http.HttpHeaders){hop?.let{headers.add(HOP_KEY,hop.toString())}headers.add(REQUEST_ID_KEY,requestId)headers.add(SESSION_ID_KEY,sessionId)}
}
结论
Spring Cloud提供了许多可以在开发微服务时直接使用的组件。 当需求开始偏离提供的需求时,可以利用底层Spring Framework的灵活性来编码那些需求。
- 春云侦探
- 使用HandlerInterceptor拦截请求
- 注册拦截器
- ClientHttpRequestInterceptor
翻译自: https://blog.frankel.ch/http-headers-management-with-spring/