SpringCloud:搭建基于Gateway的微服务网关(二)

1.引入相关依赖

pom文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>OpenAPI</artifactId>
        <groupId>com.fdzang.microservice</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>api-gateway</artifactId>

    <dependencies>
     <!-- 公共模块引入了web模块,会与gateway产生冲突,故排除 -->
<dependency> <groupId>com.fdzang.microservice</groupId> <artifactId>api-common</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency>
     <!-- 引入gateway模块 -->     <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>${spring.cloud.starter.version}</version> </dependency>
     <!-- 引入eureka模块 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>${spring.cloud.starter.version}</version> </dependency>
     <!-- 引入openfeign模块,这里不要用feign,Springboot2.0已弃用 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>${spring.cloud.starter.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>${spring.cloud.starter.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>${spring.boot.version}</version> <optional>true</optional> </dependency> </dependencies> </project>

2.配置Gateway

server:
  port: 7000

#注册到eureka eureka: client: service-url: defaultZone: http://127.0.0.1:7003/eureka/
#配置gateway拦截规则 spring: application: name: api-gateway cloud: gateway: discovery: locator: enabled: true routes: - id: gateway uri: http://www.baidu.com predicates: - Path=/**
#这里定义了鉴权的服务名,以及白名单 auth: service-id: api-auth-v1 gateway: white: - /login #这里是id生成器的配置,Twitter-Snowflake IdWorker: workerId: 122 datacenterId: 1231

3.过滤器

3.1.ID生成拦截

对每个请求生成一个唯一的请求id

package com.fdzang.microservice.gateway.gateway;

import com.fdzang.microservice.gateway.util.GatewayConstant;
import com.fdzang.microservice.gateway.util.IdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 生成一个请求的特定id
 * @author tanghu
 * @Date: 2019/11/5 18:42
 */
@Slf4j
@Component
public class SerialNoFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        String requestId= request.getHeaders().getFirst(GatewayConstant.REQUEST_TRACE_ID);
        if (StringUtils.isEmpty(requestId)) {
            Object attribute = exchange.getAttribute(GatewayConstant.REQUEST_TRACE_ID);
            if (attribute == null) {
                requestId = String.valueOf(IdWorker.getWorkerId());
                exchange.getAttributes().put(GatewayConstant.REQUEST_TRACE_ID,requestId);
            }
        }else{
            exchange.getAttributes().put(GatewayConstant.REQUEST_TRACE_ID,requestId);
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return GatewayConstant.Order.SERIAL_NO_ORDER;
    }
}

3.2.鉴权拦截

获取请求头中的鉴权信息,对信息校验,这里暂时没有做(AuthResult authService.auth(AuthRequest request)),这里需求请求其他模块对请求信息进行校验,返回校验结果

package com.fdzang.microservice.gateway.gateway;

import com.fdzang.microservice.common.entity.auth.AuthCode;
import com.fdzang.microservice.common.entity.auth.AuthRequest;
import com.fdzang.microservice.common.entity.auth.AuthResult;
import com.fdzang.microservice.gateway.service.AuthService;
import com.fdzang.microservice.gateway.util.GatewayConstant;
import com.fdzang.microservice.gateway.util.WhiteUrl;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 权限校验
 * @author tanghu
 * @Date: 2019/10/22 18:00
 */
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private AuthService authService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestId = exchange.getAttribute(GatewayConstant.REQUEST_TRACE_ID);
        String url = exchange.getRequest().getURI().getPath();

        ServerHttpRequest request = exchange.getRequest();

        //跳过白名单
        if(null != WhiteUrl.getWhite() && WhiteUrl.getWhite().contains(url)){
            return chain.filter(exchange);
        }

        //获取权限校验部分
        //Authorization: gateway:{AccessId}:{Signature}
        String authHeader = exchange.getRequest().getHeaders().getFirst(GatewayConstant.AUTH_HEADER);
        if(StringUtils.isBlank(authHeader)){
            log.warn("request has no authorization header, uuid:{}, request:{}",requestId, url);

            throw new IllegalArgumentException("bad request");
        }

        List<String> auths = Splitter.on(":").trimResults().omitEmptyStrings().splitToList(authHeader);
        if(CollectionUtils.isEmpty(auths) || auths.size() != 3 || !GatewayConstant.AUTH_LABLE.equals(auths.get(0))){
            log.warn("bad authorization header, uuid:{}, request:[{}], header:{}",
                    requestId, url, authHeader);

            throw new IllegalArgumentException("bad request");
        }

        //校验时间戳是否合法
        String timestamp = exchange.getRequest().getHeaders().getFirst(GatewayConstant.TIMESTAMP_HEADER);
        if (StringUtils.isBlank(timestamp) || isTimestampExpired(timestamp)) {
            log.warn("wrong timestamp:{}, uuid:{}, request:{}",
                    timestamp, requestId, url);
        }

        String accessId = auths.get(1);
        String sign = auths.get(2);

        String stringToSign = getStringToSign(request, timestamp);

        AuthRequest authRequest = new AuthRequest();
        authRequest.setAccessId(accessId);
        authRequest.setSign(sign);
        authRequest.setStringToSign(stringToSign);
        authRequest.setHttpMethod(request.getMethodValue());
        authRequest.setUri(url);

        AuthResult authResult = authService.auth(authRequest);

        if (authResult.getStatus() != AuthCode.SUCEESS.getAuthCode()) {
            log.warn("checkSign failed, uuid:{},  accessId:{}, request:[{}], error:{}",
                    requestId, accessId, url, authResult.getDescription());
            throw new RuntimeException(authResult.getDescription());
        }

        log.info("request auth finished, uuid:{}, orgCode:{}, userName:{}, accessId:{}, request:{}, serviceName:{}",
                requestId, authResult.getOrgCode(),
                authResult.getUsername(), accessId,
                url, authResult.getServiceName());

        exchange.getAttributes().put(GatewayConstant.SERVICE_NAME,authResult.getServiceName());

        return chain.filter(exchange);
    }

    /**
     * 获取原始字符串(签名前)
     * @param request
     * @param timestamp
     * @return
     */
    private String getStringToSign(ServerHttpRequest request, String timestamp){
        // headers
        TreeMap<String, String> headersInSign = new TreeMap<>();
        HttpHeaders headers = request.getHeaders();
        for (Map.Entry<String,List<String>> header:headers.entrySet()) {
            String key = header.getKey();
            if (key.startsWith(GatewayConstant.AUTH_HEADER_PREFIX)) {
                headersInSign.put(key, header.getValue().get(0));
            }
        }

        StringBuilder headerStringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : headersInSign.entrySet()) {
            headerStringBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
        }
        String headerString = null;
        if (headerStringBuilder.length() != 0) {
            headerString = headerStringBuilder.deleteCharAt(headerStringBuilder.length()-1).toString();
        }

        // Url_String
        TreeMap<String, String> paramsInSign = new TreeMap<>();
        MultiValueMap<String, String> parameterMap = request.getQueryParams();
        if (MapUtils.isNotEmpty(parameterMap)) {
            for (Map.Entry<String, List<String>> entry : parameterMap.entrySet()) {
                paramsInSign.put(entry.getKey(), entry.getValue().get(0));
            }
        }

        // 原始url
        String originalUrl = request.getURI().getPath();

        StringBuilder uriStringBuilder = new StringBuilder(originalUrl);
        if (!parameterMap.isEmpty()) {
            uriStringBuilder.append("?");
            for (Map.Entry<String, String> entry : paramsInSign.entrySet()) {
                uriStringBuilder.append(entry.getKey());
                if (StringUtils.isNotBlank(entry.getValue())) {
                    uriStringBuilder.append("=").append(entry.getValue());
                }
                uriStringBuilder.append("&");
            }
            uriStringBuilder.deleteCharAt(uriStringBuilder.length()-1);
        }

        String uriString = uriStringBuilder.toString();

        String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);

        //这里可以对请求参数进行MD5校验,暂时不做
        String contentMd5 = headers.getFirst(GatewayConstant.CONTENTE_MD5);

        String[] parts = {
                request.getMethodValue(),
                StringUtils.isNotBlank(contentMd5) ? contentMd5 : "",
                StringUtils.isNotBlank(contentType) ? contentType : "",
                timestamp,
                headerString,
                uriString
        };

        return Joiner.on(GatewayConstant.STRING_TO_SIGN_DELIM).skipNulls().join(parts);
    }

    /**
     * 校验时间戳是否超时
     * @param timestamp
     * @return
     */
    private boolean isTimestampExpired(String timestamp){
        long l = NumberUtils.toLong(timestamp, 0L);
        if (l == 0) {
            return true;
        }

        return Math.abs(System.currentTimeMillis() - l) > GatewayConstant.EXPIRE_TIME_SECONDS *1000;
    }

    @Override
    public int getOrder() {
        return GatewayConstant.Order.AUTH_ORDER;
    }
}

3.3.服务分发

根据鉴权后的结果能得到服务名,然后重写路由以及请求,对该次请求进行转发

package com.fdzang.microservice.gateway.gateway;

import com.fdzang.microservice.gateway.util.GatewayConstant;
import com.fdzang.microservice.gateway.util.WhiteUrl;
import com.google.common.base.Splitter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author tanghu
 * @Date: 2019/11/6 15:39
 */
@Slf4j
@Component
public class ModifyRequestFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        ServerHttpRequest request = exchange.getRequest();

        //跳过白名单
        if(null != WhiteUrl.getWhite() && WhiteUrl.getWhite().contains(url)){
            return chain.filter(exchange);
        }

        String serviceName = exchange.getAttribute(GatewayConstant.SERVICE_NAME);

        //修改路由
        Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
        Route newRoute = Route.async()
                .asyncPredicate(route.getPredicate())
                .filters(route.getFilters())
                .id(route.getId())
                .order(route.getOrder())
                .uri(GatewayConstant.URI.LOAD_BALANCE+serviceName).build();

        exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR,newRoute);

        //修改请求路径
        List<String> strings = Splitter.on("/").omitEmptyStrings().trimResults().limit(3).splitToList(url);
        String newServletPath = "/" + strings.get(2);

        ServerHttpRequest newRequest = request.mutate().path(newServletPath).build();

        return chain.filter(exchange.mutate().request(newRequest).build());
    }

    @Override
    public int getOrder() {
        return GatewayConstant.Order.MODIFY_REQUEST_ORDER;
    }
}

3.4.统一响应

对响应进行统一封装

package com.fdzang.microservice.gateway.gateway;

import com.alibaba.fastjson.JSON;
import com.fdzang.microservice.common.entity.ApiResult;
import com.fdzang.microservice.gateway.entity.GatewayError;
import com.fdzang.microservice.gateway.entity.GatewayResult;
import com.fdzang.microservice.gateway.entity.GatewayResultEnums;
import com.fdzang.microservice.gateway.util.GatewayConstant;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;

/**
 * @author tanghu
 * @Date: 2019/11/7 8:58
 */
@Slf4j
@Component
public class ModifyResponseFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestId = exchange.getAttribute(GatewayConstant.REQUEST_TRACE_ID);
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        //释放掉内存
                        DataBufferUtils.release(dataBuffer);

                        String originalbody = new String(content, Charset.forName("UTF-8"));
                        String finalBody = originalbody;

                        ApiResult apiResult = JSON.parseObject(originalbody,ApiResult.class);

                        GatewayResult result = new GatewayResult();
                        result.setCode(GatewayResultEnums.SUCC.getCode());
                        result.setMsg(GatewayResultEnums.SUCC.getMsg());
                        result.setReq_id(requestId);
                        if (apiResult.getCode() == null && apiResult.getMsg() == null) {
                            // 尝试解析body为网关的错误信息
                            GatewayError gatewayError = JSON.parseObject(originalbody,GatewayError.class);
                            result.setSub_code(gatewayError.getStatus());
                            result.setSub_msg(gatewayError.getMessage());
                        } else {
                            result.setSub_code(apiResult.getCode());
                            result.setSub_msg(apiResult.getMsg());
                        }

                        result.setData(apiResult.getData());

                        finalBody = JSON.toJSONString(result);

                        return bufferFactory.wrap(finalBody.getBytes());
                    }));
                }

                return super.writeWith(body);
            }
        };
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return GatewayConstant.Order.MODIFY_RESPONSE_ORDER;
    }
}

4.测试

D:\java\jdk1.8\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\IDEA\IntelliJ IDEA 2018.2\lib\idea_rt.jar=11647:D:\IDEA\IntelliJ IDEA 2018.2\bin" -Dfile.encoding=UTF-8 -classpath "D:\IDEA\IntelliJ IDEA 2018.2\lib\idea_rt.jar;D:\IDEA\IntelliJ IDEA 2018.2\plugins\junit\lib\junit-rt.jar;D:\IDEA\IntelliJ IDEA 2018.2\plugins\junit\lib\junit5-rt.jar;D:\java\jdk1.8\jre\lib\charsets.jar;D:\java\jdk1.8\jre\lib\deploy.jar;D:\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\java\jdk1.8\jre\lib\ext\localedata.jar;D:\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\java\jdk1.8\jre\lib\ext\sunec.jar;D:\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\java\jdk1.8\jre\lib\javaws.jar;D:\java\jdk1.8\jre\lib\jce.jar;D:\java\jdk1.8\jre\lib\jfr.jar;D:\java\jdk1.8\jre\lib\jfxswt.jar;D:\java\jdk1.8\jre\lib\jsse.jar;D:\java\jdk1.8\jre\lib\management-agent.jar;D:\java\jdk1.8\jre\lib\plugin.jar;D:\java\jdk1.8\jre\lib\resources.jar;D:\java\jdk1.8\jre\lib\rt.jar;D:\MicroService\OpenAPI\api-mock\target\test-classes;D:\MicroService\OpenAPI\api-mock\target\classes;D:\Maven\repository\com\alibaba\fastjson\1.2.50\fastjson-1.2.50.jar;D:\Maven\repository\org\projectlombok\lombok\1.18.8\lombok-1.18.8.jar;D:\Maven\repository\org\apache\httpcomponents\httpclient\4.2.1\httpclient-4.2.1.jar;D:\Maven\repository\commons-logging\commons-logging\1.1.1\commons-logging-1.1.1.jar;D:\Maven\repository\org\apache\httpcomponents\httpcore\4.2.1\httpcore-4.2.1.jar;D:\Maven\repository\org\apache\commons\commons-lang3\3.8.1\commons-lang3-3.8.1.jar;D:\Maven\repository\commons-codec\commons-codec\1.10\commons-codec-1.10.jar;D:\Maven\repository\org\slf4j\slf4j-api\1.7.7\slf4j-api-1.7.7.jar;D:\Maven\repository\org\slf4j\jcl-over-slf4j\1.7.7\jcl-over-slf4j-1.7.7.jar;D:\Maven\repository\ch\qos\logback\logback-classic\1.1.2\logback-classic-1.1.2.jar;D:\Maven\repository\ch\qos\logback\logback-core\1.1.2\logback-core-1.1.2.jar;D:\Maven\repository\org\eclipse\jetty\jetty-util\9.3.7.v20160115\jetty-util-9.3.7.v20160115.jar;D:\Maven\repository\junit\junit\4.5\junit-4.5.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.fdzang.microservice.mock.Demo,testGet
header:key: X-TH-OpenAPI-Timestampheader:values: 1573093554201
10:25:54.961 [main] INFO  c.f.microservice.mock.util.SignUtil - StringToSign:
GET


1573093554201
/v2/base/zuul/tag/getMostUsedTags?from=2017-11-25 00:00:00&plate_num=部A11110&to=2017-11-30 00:00:00
10:25:54.979 [main] INFO  c.f.microservice.mock.util.HttpUtil - sign:Y+usbpHlwOw4F2sq4b0pNjgXGDAXoYgs1syOOPxPFAE=
header:key: Authorizationheader:values: gateway:omwcs8:Y+usbpHlwOw4F2sq4b0pNjgXGDAXoYgs1syOOPxPFAE=
header:key: X-TH-OpenAPI-Timestampheader:values: 1573093554201
http://127.0.0.1:7000 /v2/base/zuul/tag/getMostUsedTags
10:25:55.936 [main] DEBUG o.a.h.i.c.BasicClientConnectionManager - Get connection for route {}->http://127.0.0.1:7000
10:25:55.947 [main] DEBUG o.a.h.i.c.DefaultClientConnectionOperator - Connecting to 127.0.0.1:7000
10:25:55.973 [main] DEBUG o.a.h.c.protocol.RequestAddCookies - CookieSpec selected: best-match
10:25:56.058 [main] DEBUG o.a.h.c.protocol.RequestAuthCache - Auth cache not set in the context
10:25:56.058 [main] DEBUG o.a.h.c.p.RequestProxyAuthentication - Proxy auth state: UNCHALLENGED
10:25:56.059 [main] DEBUG o.a.h.impl.client.DefaultHttpClient - Attempt 1 to execute request
10:25:56.059 [main] DEBUG o.a.h.i.conn.DefaultClientConnection - Sending request: GET /v2/base/zuul/tag/getMostUsedTags?plate_num=%E9%83%A8A11110&from=2017-11-25+00%3A00%3A00&to=2017-11-30+00%3A00%3A00 HTTP/1.1
10:25:56.060 [main] DEBUG org.apache.http.wire - >> "GET /v2/base/zuul/tag/getMostUsedTags?plate_num=%E9%83%A8A11110&from=2017-11-25+00%3A00%3A00&to=2017-11-30+00%3A00%3A00 HTTP/1.1[\r][\n]"
10:25:56.061 [main] DEBUG org.apache.http.wire - >> "Authorization: gateway:omwcs8:Y+usbpHlwOw4F2sq4b0pNjgXGDAXoYgs1syOOPxPFAE=[\r][\n]"
10:25:56.061 [main] DEBUG org.apache.http.wire - >> "X-TH-OpenAPI-Timestamp: 1573093554201[\r][\n]"
10:25:56.061 [main] DEBUG org.apache.http.wire - >> "Host: 127.0.0.1:7000[\r][\n]"
10:25:56.063 [main] DEBUG org.apache.http.wire - >> "Connection: Keep-Alive[\r][\n]"
10:25:56.063 [main] DEBUG org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.2.1 (java 1.5)[\r][\n]"
10:25:56.063 [main] DEBUG org.apache.http.wire - >> "[\r][\n]"
10:25:56.063 [main] DEBUG org.apache.http.headers - >> GET /v2/base/zuul/tag/getMostUsedTags?plate_num=%E9%83%A8A11110&from=2017-11-25+00%3A00%3A00&to=2017-11-30+00%3A00%3A00 HTTP/1.1
10:25:56.063 [main] DEBUG org.apache.http.headers - >> Authorization: gateway:omwcs8:Y+usbpHlwOw4F2sq4b0pNjgXGDAXoYgs1syOOPxPFAE=
10:25:56.063 [main] DEBUG org.apache.http.headers - >> X-TH-OpenAPI-Timestamp: 1573093554201
10:25:56.063 [main] DEBUG org.apache.http.headers - >> Host: 127.0.0.1:7000
10:25:56.063 [main] DEBUG org.apache.http.headers - >> Connection: Keep-Alive
10:25:56.063 [main] DEBUG org.apache.http.headers - >> User-Agent: Apache-HttpClient/4.2.1 (java 1.5)
10:25:59.858 [main] DEBUG org.apache.http.wire - << "HTTP/1.1 200 OK[\r][\n]"
10:25:59.860 [main] DEBUG org.apache.http.wire - << "transfer-encoding: chunked[\r][\n]"
10:25:59.860 [main] DEBUG org.apache.http.wire - << "Content-Type: application/json;charset=UTF-8[\r][\n]"
10:25:59.860 [main] DEBUG org.apache.http.wire - << "Date: Thu, 07 Nov 2019 02:25:59 GMT[\r][\n]"
10:25:59.860 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
10:25:59.861 [main] DEBUG o.a.h.i.conn.DefaultClientConnection - Receiving response: HTTP/1.1 200 OK
10:25:59.861 [main] DEBUG org.apache.http.headers - << HTTP/1.1 200 OK
10:25:59.861 [main] DEBUG org.apache.http.headers - << transfer-encoding: chunked
10:25:59.861 [main] DEBUG org.apache.http.headers - << Content-Type: application/json;charset=UTF-8
10:25:59.861 [main] DEBUG org.apache.http.headers - << Date: Thu, 07 Nov 2019 02:25:59 GMT
10:25:59.864 [main] DEBUG o.a.h.impl.client.DefaultHttpClient - Connection can be kept alive indefinitely
10:25:59.867 [main] DEBUG org.apache.http.wire - << "10c[\r][\n]"
10:25:59.868 [main] DEBUG org.apache.http.wire - << "{"code":0,"data":[{"tagPublishedRefCount":3,"tagTitle":"Solo","id":"1533101769023","tagReferenceCount":3},{"tagPublishedRefCount":1,"tagTitle":"tetet","id":"1559285894006","tagReferenceCount":1}],"msg":"succ","req_id":"2627469547766022144","sub_code":0,"sub_msg":"ok"}"
10:25:59.868 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
10:25:59.868 [main] DEBUG org.apache.http.wire - << "0[\r][\n]"
10:25:59.868 [main] DEBUG org.apache.http.wire - << "[\r][\n]"
10:25:59.868 [main] DEBUG o.a.h.i.c.BasicClientConnectionManager - Releasing connection org.apache.http.impl.conn.ManagedClientConnectionImpl@6ab7a896
10:25:59.868 [main] DEBUG o.a.h.i.c.BasicClientConnectionManager - Connection can be kept alive indefinitely
10:25:59.868 [main] INFO  com.fdzang.microservice.mock.Demo - {"code":0,"data":[{"tagPublishedRefCount":3,"tagTitle":"Solo","id":"1533101769023","tagReferenceCount":3},{"tagPublishedRefCount":1,"tagTitle":"tetet","id":"1559285894006","tagReferenceCount":1}],"msg":"succ","req_id":"2627469547766022144","sub_code":0,"sub_msg":"ok"}

Process finished with exit code 0

猜你喜欢

转载自www.cnblogs.com/fdzang/p/11810932.html