Retrofit2+Okhttp3 network request

1. Introducing dependencies

        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>retrofit</artifactId>
            <version>2.0.0-beta4</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.retrofit2</groupId>
            <artifactId>converter-jackson</artifactId>
            <version>2.0.0-beta4</version>
        </dependency>

        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.1.2</version>
        </dependency>

2. Example of retrofit usage

Create a parent class

@Slf4j
public class DdtClient {

    protected Retrofit retrofit;

    @Autowired
    public DdtClient(String apiBaseUrl) {

        retrofit = createRetrofit(apiBaseUrl);
    }

    private Retrofit createRetrofit(String apiBaseUrl) {
                Interceptor interceptor = chain -> {
                    Request newRequest = chain.request().newBuilder().addHeader("jtoken",  Utils.createTestToken("13100001234")).build();
            return chain.proceed(newRequest);
        };


        X509TrustManager xtm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };

        SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("SSL");

            sslContext.init(null, new TrustManager[]{xtm}, new SecureRandom());

        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            e.printStackTrace();
        }
        HostnameVerifier DO_NOT_VERIFY = (hostname, session) -> true;


        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.interceptors().add(interceptor);
        //添加拦截器
        builder.interceptors().add(new MonitorRequestInterceptor());
        builder.interceptors().add(new LogRequestInterceptor());
        builder.interceptors().add(new Retry(3));

        assert sslContext != null;
        OkHttpClient client = builder
                .connectTimeout(20, TimeUnit.SECONDS)
                .writeTimeout(20, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .sslSocketFactory(sslContext.getSocketFactory())
                .hostnameVerifier(DO_NOT_VERIFY)
                .build();

        return new Retrofit
                .Builder()
                .baseUrl(apiBaseUrl)
                .addConverterFactory(JacksonConverterFactory.create())
                .client(client)
                .build();
    }

    /**
     * 自定义的,重试N次的拦截器
     * 通过:addInterceptor 设置
     */
    public static class Retry implements Interceptor {
        public int maxRetry;//最大重试次数
        private int retryNum = 0;//假如设置为3次重试的话,则最大可能请求4次(默认1次+3次重试)
        public Retry(int maxRetry) {
            this.maxRetry = maxRetry;
        }
        @Override
        public Response intercept(@NonNull Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            while (!response.isSuccessful() && retryNum < maxRetry) {
                retryNum++;
                log.info("Retry num:"+retryNum);
                response = chain.proceed(request);
            }
            return response;
        }
    }
}

Create an interface class to store the interface that rpc needs to call

public interface CloudApi {

    /**
     * 获取客户明细
     * @param page
     * @param size
     * @return
     */

    @GET("/v1/customers")
    Call<PageVO<CustomerVO>> findCustomersByPage(@Query("page") Integer page, @Query("size") Integer size);
}

3. Create interceptor class

1. Log Interceptor

Realize log customization.

@Slf4j
public class LogRequestInterceptor implements Interceptor {


    @NotNull
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        long tx = response.sentRequestAtMillis();
        long rx = response.receivedResponseAtMillis();

        long costMillis = rx-tx;

        log(request, response, costMillis);

        return response;
    }

    private void log(Request request,Response response, long costMillis) throws IOException {
        String uri = request.url().toString();
        String method = request.method();
        int status = response.code();

        String requestString = getRequestString(request);

        LogRecord logRecord = new LogRecord()
                .setUri(uri)
                .setHttpMethod(method)
                .setReqHeaders(getHttpHeader(request.headers()))
                .setReqBody(requestString)
                .setCostMillis((int) costMillis)
                .setRespHeaders(getHttpHeader(response.headers()))
                .setStatus(status)
                .setRespBody(response.peekBody(500).string());

        log.info("[AUDITLOG::RETROFITTHIRDPART] {}", JsonUtils.toJsonString(logRecord));
    }

    private HttpHeaders getHttpHeader(Headers headers) {
        HttpHeaders httpHeaders = new HttpHeaders();
        for (int i = 0, count = headers.size(); i < count; i++) {
            String name = headers.name(i);
            // Skip headers from the request body as they are explicitly logged above.
            httpHeaders.set(name,headers.value(i));
        }
        return httpHeaders;
    }

    private String getRequestString(Request request) {
        RequestBody requestBody = request.body();
        if (ObjectUtil.isEmpty(requestBody)){
            return null;
        }
        Buffer buffer = new Buffer();
        try {
            requestBody.writeTo(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //编码设为UTF-8
        Charset charset = StandardCharsets.UTF_8;
        MediaType contentType = requestBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(StandardCharsets.UTF_8);
        }
        //拿到request
        return buffer.readString(charset);
    }


    @Data
    @Accessors(chain = true)
    public static class LogRecord {
        private String httpMethod;
        private String uri;
        private HttpHeaders reqHeaders;
        private String reqBody;

        private Integer costMillis;
        private HttpHeaders respHeaders;
        private Integer status;
        private String respBody;
    }
}

2. Monitor blocker

@Slf4j
public class MonitorRequestInterceptor implements Interceptor {

    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {
        Request request = chain.request();
        Response response = chain.proceed(request);
        long tx = response.sentRequestAtMillis();
        long rx = response.receivedResponseAtMillis();

        MonitorThirdPartRequest.monitor(new RequestLatency()
                .setCode(Objects.isNull(response) ? -1 : response.code())
                .setMethod(request.method())
                .setPath(request.url().encodedPath())
                .setCostMillis(rx-tx)
        );
        return response;
    }
}

Fourth, create an interface implementation class

Create an interface implementation class and inherit the retrofit class

@Component
@Slf4j
public class CustomCloudClient extends MiddleClient {

    private CloudApi api;

    @Autowired
    public CustomCloudClient(@Value("${cloud.api.baseUrl}") String apiBaseUrl,
                             @Value("${token.user.url}") String apiToken) {
        super(apiBaseUrl, apiToken);
        api = retrofit.create(CloudApi.class);
    }


    public PageVO<CustomerVO> findCustomersByPage(User user,Integer page, Integer size) throws IOException {
        createUserToken(user);
        Call<PageVO<CustomerVO>> call = api.findCustomersByPage(page,size);
        Response<PageVO<CustomerVO>> response = call.execute();
        if (response.code() == 200) {
            return response.body();
        } else {
            log.info("getCardsByTaskId, status:{}, message:{}", response.code(), response.message());
        }
        return null;
    }

    private String createUserToken(final User user) {
        try {
            return JwtUtils.createToken(user);
        } catch (final IllegalAccessException e) {
            log.error("", e);
            throw new IllegalStateException("BUG: cannot create user token");
        }
    }
}

Five, custom Converter.Factory

Converter.Factory, definitely by addConverterFactorysetting

   Retrofit retrofit = new Retrofit
                .Builder()
                .baseUrl(apiBaseUrl)
                .addConverterFactory(StringConverterFactory.create())
                .client(client)
                .build();

Create a converter class, inheritConverter.Factory

public class StringConverterFactory extends Converter.Factory {

    public static StringConverterFactory create() {
        return new StringConverterFactory();
    }

    private StringConverterFactory() {

    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        return new StringResponseBodyConverter();
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        return new StringRequestBodyConverter();
    }
}
  

Define RequestBody

public class StringRequestBodyConverter  implements Converter<String, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    StringRequestBodyConverter() {
    }

    @Override public RequestBody convert(String value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        writer.write(value);
        writer.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}
  

Define ResponseBody

public class StringResponseBodyConverter implements Converter<ResponseBody, String> {
    @Override
    public String convert(ResponseBody value) throws IOException {
        try {
            return value.string();
        } finally {
            value.close();
        }
    }
}

When using it, you can

 Retrofit retrofit = new Retrofit.Builder()
.callFactory(new OkHttpClient())               .baseUrl("http://example/springmvc_users/user/")
//.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(new UserConverterFactory())
            .build();

Different converters can use different Client classes

Guess you like

Origin blog.csdn.net/songkai558919/article/details/121590914