Article directory
- Introduction
- practice
-
- HttpClientBuilder
- Customized chain of responsibility
- test
Introduction
HttpClientBuilder is an http client construction class of Apache. By inheriting the construction class, signature verification can be added, so that signature verification can be carried when sending requests uniformly.
Customized MyHttpClientBuilder adds a new link to the chain of responsibility
Practice
HttpClientBuilder
HttpClientBuilder has many public methods, but they are all final definitions and cannot be overridden by subclasses.
The key transformation lies in decorateProtocolExec
@NoArgsConstructor public class MyHttpClientBuilder extends HttpClientBuilder { private String name; private String password; public static MyHttpClientBuilder create() { return new MyHttpClientBuilder(); } public MyHttpClientBuilder setName(String name) { this.name = name; return this; } public MyHttpClientBuilder setPassword(String password) { this.password = password; return this; } /** * Create main chain */ @Override ProteCted ClientexecChain CreateMainexec (httprequestexecutor requestexec, httpClientConnectionManager, ConnectionReuseSESTRATEGY Reusestrategy, Conn EctionKEPALIVESTRATEGY KeepaliveStrategy, httpprocessor proxyhttpprocessor, authenticationStrateAutrategy, AuthenticationsStrategy ProxyAut hstraategy, usertokenhandler userTokenhandler) {{ return super.createMainExec(requestExec, connManager, reuseStrategy, keepAliveStrategy, proxyHttpProcessor, targetAuthStrategy, proxyAuthStrategy, userTokenHandler); } /** * Decorative main chain */ @Override protected ClientExecChain decorateMainExec(ClientExecChain mainExec) { return super.decorateMainExec(mainExec); } /** * decorative */ @Override protected ClientExecChain decorateProtocolExec(ClientExecChain protocolExec) { // return super.decorateProtocolExec(protocolExec); return new MyClientExecChain(name, password, protocolExec); } /** * Add http client for multi-client management */ @Override protected void addCloseable(Closeable closeable) { super.addCloseable(closeable); } /** * Initialize InternalHttpClient */ @Override public CloseableHttpClient build() { return super.build(); } }
Customized chain of responsibility
Define the chain of responsibility and add the request header token
public class MyClientExecChain implements ClientExecChain { private final String name; private final String password; private final ClientExecChain mainExec; public MyClientExecChain(String name,String password,ClientExecChain mainExec){ this.name = name; this.password = password; this.mainExec = mainExec; } /** * The chain of responsibility needs to stipulate the conditions for its effectiveness * */ @Override public CloseableHttpResponse execute(HttpRoute route, HttpRequestWrapper request, HttpClientContext clientContext, HttpExecutionAware execAware) throws IOException, HttpException { //Domain name to control access if ( Objects.nonNull(request.getURI().getHost()) & amp; & amp; request.getURI().getHost().endsWith("127.0.0.1")) { return executeMy(route, request, clientContext, execAware); } else { return mainExec.execute(route, request, clientContext, execAware); } } /** * Add content * */ private CloseableHttpResponse executeMy(HttpRoute route, HttpRequestWrapper request, HttpClientContext clientContext, HttpExecutionAware execAware) throws IOException, HttpException{ //Add authentication information request.addHeader("token", name + "-" + password); //Execute mainExec CloseableHttpResponse response = mainExec.execute(route, request, clientContext, execAware); // Verify successful response StatusLine statusLine = response.getStatusLine(); if (statusLine.getStatusCode() >= 200 & amp; & amp; statusLine.getStatusCode() < 300) { // Convert to an entity with repeatable responses convertToRepeatableResponseEntity(response); if (!(request.getOriginal() instanceof WxPayV3DownloadHttpGet)) { if (!validate(response)) { throw new HttpException("Signature verification failed"); } } } return response; } /** * Convert to an entity with repeatable responses * */ protected void convertToRepeatableResponseEntity(CloseableHttpResponse response) throws IOException { HttpEntity entity = response.getEntity(); if (entity != null & amp; & amp; !entity.isRepeatable()) { response.setEntity(newRepeatableEntity(entity)); } } /** * New entity * */ protected HttpEntity newRepeatableEntity(HttpEntity entity) throws IOException { byte[] content = EntityUtils.toByteArray(entity); ByteArrayEntity newEntity = new ByteArrayEntity(content); newEntity.setContentEncoding(entity.getContentEncoding()); newEntity.setContentType(entity.getContentType()); return newEntity; } /** * Verification * */ private boolean validate(CloseableHttpResponse response) throws IOException { // If it is not in json format, return directly if (!ContentType.APPLICATION_JSON.getMimeType() .equals(ContentType.parse( String.valueOf(response.getFirstHeader("Content-Type").getValue()) ).getMimeType())) { return true; } // Get header information Header name = response.getFirstHeader("name"); //No data exists if (name == null) { return false; } return !Objects.equals(name,this.name); } }
Test
When requesting here, it is 127.0.0.1, which is also the domain name intercepted by the chain of responsibility.
@Test void contextLoads() { String url = "http://127.0.0.1:9090/http/test"; WxPayUnifiedOrderV3Request request = new WxPayUnifiedOrderV3Request(); // Transaction code request.setOutTradeNo("5566"); //Notification address (callback address) request.setNotifyUrl("https://api.qq.com/"); request.setDescription("This is a description"); WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer(); // Merchant openid payer.setOpenid("openid"); request.setPayer(payer); //Build amount information WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount(); //Set currency information amount.setCurrency("CNY"); //Set the amount, calculated in points here amount.setTotal(BigDecimal.ONE.multiply(BigDecimal.valueOf(100)).intValue()); request.setAmount(amount); String res = post(url,JSON.toJSONString(request)); log.info("http request ended:",res); } private String post(String url,String entity){ HttpPost httpPost = new HttpPost(url); httpPost.setConfig(RequestConfig.custom() //The time to get the connection from the connection pool .setConnectionRequestTimeout(1000) // Time to establish connection .setConnectTimeout(1000) //Time to read data .setSocketTimeout(3000) .build()); httpPost.setEntity(new StringEntity(entity, ContentType.create("application/json", "utf-8"))); CloseableHttpClient httpClient = MyHttpClientBuilder .create() .setName("zhang") .setPassword("1234").build(); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { int statusCode = response.getStatusLine().getStatusCode(); //The post method may not return a value String responseString = null; if (response.getEntity() != null) { responseString = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); } //Status code judgment 200 204 successful if (HttpStatus.SC_OK == statusCode || HttpStatus.SC_NO_CONTENT == statusCode) { this.log.info("\ [Request address]: {}\ [Request data]: {}\ [Response data]: {}", url, entity, responseString); return responseString; } //An error message is returned throw new MyException(responseString); } catch (Exception e) { log.error("Exception:",e); } finally { // close connection httpPost.releaseConnection(); } return null; }