Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring boot 如何使用外部拦截器/解码器以自定义格式记录请求-响应?_Spring Boot_Spring Cloud Feign_Feign - Fatal编程技术网

Spring boot 如何使用外部拦截器/解码器以自定义格式记录请求-响应?

Spring boot 如何使用外部拦截器/解码器以自定义格式记录请求-响应?,spring-boot,spring-cloud-feign,feign,Spring Boot,Spring Cloud Feign,Feign,我正在为springboot开发一个定制的日志框架,用于记录rest模板请求和响应,目前运行良好。我正试图为“外国客户”实现同样的功能,我面临着两个问题 对于请求日志记录,我利用了假请求拦截器,它工作正常,唯一的问题是我无法检索完整的请求URL。 下面的方法只提供了相对URL requestTemplate.url() 要记录响应,我唯一能找到的方法是ResponseDecoder。在那里,我可以检索除有效载荷以外的所有内容。从访问有效负载时 InputStream is = respons

我正在为springboot开发一个定制的日志框架,用于记录rest模板请求和响应,目前运行良好。我正试图为“外国客户”实现同样的功能,我面临着两个问题

  • 对于请求日志记录,我利用了
    假请求拦截器
    ,它工作正常,唯一的问题是我无法检索完整的请求URL。 下面的方法只提供了相对URL

    requestTemplate.url()
    
  • 要记录响应,我唯一能找到的方法是
    ResponseDecoder
    。在那里,我可以检索除有效载荷以外的所有内容。从访问有效负载时

    InputStream is = response.body().asInputStream();
    String payload = new String(IOUtils.toByteArray(is));
    
  • 此方法可以工作,但原始流被关闭,因为日志记录可以正常进行,但客户端在返回响应时抛出异常

    “试图打开关闭的流”


    我想知道是否有更好的方法可以像SpringREST模板一样,在Feign中记录请求响应。或者,如果我所采用的方法没有问题,请帮助我解决上述问题。

    您可以配置一个自定义
    feign.Logger
    实例来处理此问题。有两个内置的,
    JavaLogger
    使用
    java.util.logging
    Slf4JLogger
    使用
    slf4j
    。您可以通过扩展
    feign.logger
    并将其注册为
    @Bean
    来创建自己的记录器实现

    该记录器应在Spring之前获取,并在您的
    佯装客户端注册。下面是让您开始学习的
    记录器
    基类:

    受保护的抽象无效日志(字符串配置键、字符串格式、对象…参数);
    

    创建自己的实例,实现这个方法,然后在请求之前和响应返回之后调用它。无需更新拦截器或创建响应解码器。

    在RestConfiguration中,您需要升级默认级别的logging FaignClient,并通过@Bean FaignLogger进行覆盖,如:

    @Configuration(proxyBeanMethods = false)
    @EnableCircuitBreaker
    @EnableFeignClients(basePackageClasses = [Application::class])
    class RestConfiguration: WebMvcConfigurer {
    
        @Bean
        fun feignLoggerLevel(): Logger.Level {
            return Logger.Level.FULL
        }
    
        @Bean
        fun feignLogger(): Logger {
            return FeignClientLogger()
        }
    }
    
    并实施记录器(日志格式):

    导入外部记录器
    进口外国请求
    进口国外响应
    导入feign.Util*
    导入org.slf4j.LoggerFactory
    类faignClientLogger:Logger(){
    private val log=LoggerFactory.getLogger(this::class.java)
    重写日志请求(configKey:String?,日志级别:Level?,请求:request?){
    if(请求==null)
    返回
    val feignRequest=feignRequest()
    feignRequest.method=request.httpMethod().name
    feignRequest.url=request.url()
    for(request.headers()键中的字段){
    for(值中的值或空(request.headers(),字段)){
    假装请求.addHeader(字段,值)
    }
    }
    if(request.requestBody()!=null){
    feignRequest.body=request.requestBody().asString()
    }
    log.trace(假装请求.toString())
    }
    覆盖有趣的日志和缓冲响应(
    configKey:字符串?,
    日志级别:级别?,
    答复:答复?,
    时间:长
    ):回应{
    如果(响应==null)
    返回响应
    val feignResponse=feignResponse()
    val status=响应。状态()
    faignresponse.status=response.status()
    假装回答、理由=
    (如果(response.reason()!=null&&logLevel!!>Level.NONE)“+response.reason()else”“)
    faignresponse.duration=elapsedTime
    if(logLevel!!.ordinal>=Level.HEADERS.ordinal){
    for(response.headers().keys中的字段){
    for(valuesOrEmpty(response.headers(),field)中的值){
    FaignResponse.addHeader(字段,值)
    }
    }
    if(response.body()!=null&&!(status==204 | | status==205)){
    val bodyData:ByteArray=toByteArray(response.body().asInputStream())
    if(logLevel.ordinal>=Level.FULL.ordinal&&bodyData.isNotEmpty()){
    feignResponse.body=decodeodefault(bodyData,UTF_8,“二进制数据”)
    }
    log.trace(feignResponse.toString())
    返回response.toBuilder().body(bodyData.build())
    }否则{
    log.trace(feignResponse.toString())
    }
    }
    返回响应
    }
    重写有趣的日志(p0:String?,p1:String?,vararg p2:Any?{}
    }
    类假反应{
    var状态=0
    变量原因:字符串?=null
    变量持续时间:长=0
    私有val头:MutableList=mutableListOf()
    变量正文:字符串?=null
    fun addHeader(键:String?,值:String?){
    headers.add(“$key:$value”)
    }
    重写funtostring()=
    “{”type:“response”,“status:“$status”,“duration:“$duration”,“headers:$headers”,“body:$body”,“reason:$reason”}”
    }
    类假请求{
    变量方法:字符串?=null
    变量url:字符串?=null
    私有val头:MutableList=mutableListOf()
    变量正文:字符串?=null
    fun addHeader(键:String?,值:String?){
    headers.add(“$key:$value”)
    }
    重写funtostring()=
    “{”类型“:”请求“,”方法“:”方法“,”url“:”url“,”标题“:”标题“,”正文“:$body}”
    }
    
    import feign.Logger
    import feign.Request
    import feign.Response
    import feign.Util.*
    import org.slf4j.LoggerFactory
    
    class FeignClientLogger : Logger() {
        private val log = LoggerFactory.getLogger(this::class.java)
    
        override fun logRequest(configKey: String?, logLevel: Level?, request: Request?) {
            if (request == null)
                return
    
            val feignRequest = FeignRequest()
            feignRequest.method = request.httpMethod().name
            feignRequest.url = request.url()
            for (field in request.headers().keys) {
                for (value in valuesOrEmpty(request.headers(), field)) {
                    feignRequest.addHeader(field, value)
                }
            }
    
            if (request.requestBody() != null) {
                feignRequest.body = request.requestBody().asString()
            }
    
            log.trace(feignRequest.toString())
        }
    
        override fun logAndRebufferResponse(
            configKey: String?,
            logLevel: Level?,
            response: Response?,
            elapsedTime: Long
        ): Response? {
            if (response == null)
                return response
    
            val feignResponse = FeignResponse()
            val status = response.status()
            feignResponse.status = response.status()
            feignResponse.reason =
                (if (response.reason() != null && logLevel!! > Level.NONE) " " + response.reason() else "")
            feignResponse.duration = elapsedTime
    
            if (logLevel!!.ordinal >= Level.HEADERS.ordinal) {
                for (field in response.headers().keys) {
                    for (value in valuesOrEmpty(response.headers(), field)) {
                        feignResponse.addHeader(field, value)
                    }
                }
    
                if (response.body() != null && !(status == 204 || status == 205)) {
                    val bodyData: ByteArray = toByteArray(response.body().asInputStream())
                    if (logLevel.ordinal >= Level.FULL.ordinal && bodyData.isNotEmpty()) {
                        feignResponse.body = decodeOrDefault(bodyData, UTF_8, "Binary data")
                    }
                    log.trace(feignResponse.toString())
    
                    return response.toBuilder().body(bodyData).build()
                } else {
                    log.trace(feignResponse.toString())
                }
            }
            return response
        }
    
        override fun log(p0: String?, p1: String?, vararg p2: Any?) {}
    }
    
    class FeignResponse {
        var status = 0
        var reason: String? = null
        var duration: Long = 0
        private val headers: MutableList<String> = mutableListOf()
        var body: String? = null
    
        fun addHeader(key: String?, value: String?) {
            headers.add("$key: $value")
        }
    
        override fun toString() =
            """{"type":"response","status":"$status","duration":"$duration","headers":$headers,"body":$body,"reason":"$reason"}"""
    }
    
    class FeignRequest {
        var method: String? = null
        var url: String? = null
        private val headers: MutableList<String> = mutableListOf()
        var body: String? = null
    
        fun addHeader(key: String?, value: String?) {
            headers.add("$key: $value")
        }
    
        override fun toString() =
            """{"type":"request","method":"$method","url":"$url","headers":$headers,"body":$body}"""
    }