All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alogic.remote.httpclient.HttpClientRequest Maven / Gradle / Ivy

There is a newer version: 1.6.16
Show newest version
package com.alogic.remote.httpclient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.nio.charset.Charset;

import com.alogic.remote.util.RemoteCallMetrics;
import com.alogic.tracer.Tool;
import com.alogic.tracer.TraceContext;
import com.anysoft.rrm.RRData;
import com.anysoft.rrm.RRDataHandlerFactory;
import org.apache.http.*;
import org.apache.http.client.entity.GzipCompressingEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.*;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;

import com.alogic.remote.Request;
import com.alogic.remote.Response;
import com.alogic.remote.backend.Backend;
import com.alogic.rpc.CallException;
import com.anysoft.util.Properties;
import com.anysoft.stream.Handler;

/**
 * Request
 * 
 * @author yyduan
 * @since 1.6.8.12
 * 
 * @version 1.6.8.14 
* - 优化http远程调用的超时机制
* * @version 1.6.8.15 [20170511 duanyy]
* - 增加绝对路径调用功能
* * @version 1.6.10.1 [20170910 duanyy]
* - 修正httpclient连接的“failed to respond”异常; * * @version 1.6.10.6 [20171114 duanyy]
* - 增加Filter的事件触发
* * @version 1.6.10.9 [20171124 duanyy]
* - 增加{@link #getPathInfo()}和{@link #getQueryInfo()}方法
* * @version 1.6.11.14 [duanyy 20180129]
* - 修正QueryInfo和服务器取法不一致的问题
* * @version 1.6.13.6 [20200629 duanyy]
* - 增加rpc的debug信息的输出;
* * @version 1.6.13.21 [20201021 duanyy]
* - 优化代码结构
* - 支持gzip压缩
*/ public class HttpClientRequest implements Request{ protected static final Logger LOG = LoggerFactory.getLogger(HttpClientRequest.class); protected HttpRequestBase httpRequest = null; protected CloseableHttpClient httpClient = null; protected HttpClient client = null; protected HttpClientConfig clientConfig = null; protected boolean debug = false; public HttpClientRequest(String method,CloseableHttpClient httpClient,HttpClient client,HttpClientConfig clientConfig,boolean debug){ this.httpClient = httpClient; this.client = client; this.clientConfig = clientConfig; this.debug = clientConfig.isDebug() | debug; httpRequest = getRequestByMethod(method); if (httpRequest == null){ httpRequest = new HttpPost(); } httpRequest.setConfig(clientConfig.getRequestConfig()); } public HttpRequestBase getRequestByMethod(final String method){ HttpClient.Method m = HttpClient.Method.valueOf(method.toUpperCase()); return m.createRequest(); } /** * 获取当前的URI * @return URI */ public String getURI(){ URI uri = this.httpRequest != null ? this.httpRequest.getURI() : null; return uri != null ? uri.toString() : ""; } public String getPathInfo(){ URI uri = this.httpRequest != null ? this.httpRequest.getURI() : null; return uri != null ? uri.getPath() : ""; } public String getQueryInfo(){ URI uri = this.httpRequest != null ? this.httpRequest.getURI() : null; return uri != null ? uri.getRawQuery() : ""; } /** * 获取指定的header值 * @param name header名称 * @param dft 缺省值 * @return header值 */ public String getHeader(String name,String dft){ Header header = this.httpRequest != null ? this.httpRequest.getFirstHeader(name) : null; return header == null ? dft: header.getValue(); } @Override public Request setHeader(String name, String value) { if (this.httpRequest != null){ this.httpRequest.setHeader(name, value); } return this; } @Override public Request setBody(String text) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; HttpEntity entity = new StringEntity(text,clientConfig.getEncoding()); if (clientConfig.isGzipEnable()){ entity = new GzipCompressingEntity(entity); } entityRequest.setEntity(entity); } return this; } @Override public Request setBody(byte[] body) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; HttpEntity entity = new ByteArrayEntity(body); if (clientConfig.isGzipEnable()){ entity = new GzipCompressingEntity(entity); } entityRequest.setEntity(entity); } return this; } @Override public Request setBody(InputStream in) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; HttpEntity entity = new InputStreamEntity(in); if (clientConfig.isGzipEnable()){ entity = new GzipCompressingEntity(entity); } entityRequest.setEntity(entity); } return this; } @Override public Request setMultipartBody(String formKey, String filename, String content) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setCharset(Charset.forName(clientConfig.getEncoding())); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody(formKey, content.getBytes(), ContentType.MULTIPART_FORM_DATA, filename); entityRequest.setEntity(builder.build()); } return this; } @Override public Request setMultipartBody(String formKey, String filename, byte[] content) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setCharset(Charset.forName(clientConfig.getEncoding())); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody(formKey,content, ContentType.MULTIPART_FORM_DATA, filename); entityRequest.setEntity(builder.build()); } return this; } @Override public Request setMultipartBody(String formKey, String filename, InputStream in) { if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setCharset(Charset.forName(clientConfig.getEncoding())); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); builder.addBinaryBody(formKey, in, ContentType.MULTIPART_FORM_DATA, filename); entityRequest.setEntity(builder.build()); } return this; } @Override public Request setBody(DirectOutput out){ if (httpRequest != null && httpRequest instanceof HttpEntityEnclosingRequestBase){ HttpEntityEnclosingRequestBase entityRequest = (HttpEntityEnclosingRequestBase) httpRequest; HttpEntity entity = new DirectOutputEntity(out); if (clientConfig.isGzipEnable()){ entity = new GzipCompressingEntity(entity); } entityRequest.setEntity(entity); } return this; } @Override public Response execute(String path,String key,Properties ctx) { int retryCount = 0; int autoRetry = 0; Response result = null; String lastErrorCode = "core.io_error"; String lastErrorMsg = ""; while (true){ Backend backend = null; long start = System.nanoTime(); boolean error = false; try { backend = client.getBackend(key,ctx, autoRetry > 0 ? 0 : retryCount ++ ); if (backend != null){ result = execute(path,backend,path); } break; }catch (CallException ex){ error = true; lastErrorCode = ex.getCode(); lastErrorMsg = ex.getMessage(); if (lastErrorCode.equals("core.e1602") || lastErrorCode.equals("core.e1603") || lastErrorCode.equals("core.e1604")){ //对于internal错误,属于连接错误,可以重试 autoRetry = autoRetry >= clientConfig.getAutoRetryCnt() ? 0 : autoRetry + 1; if (autoRetry > 0){ LOG.error("Internal error occurs,Retry " + autoRetry); } }else{ if (!lastErrorCode.startsWith("core")){ throw ex; } } }finally{ if (backend != null){ backend.count(System.nanoTime() - start, error); } } } if (result == null){ throw new CallException(lastErrorCode,lastErrorMsg); } return result; } @Override public Response execute(String fullPath) { String url = fullPath; long start = System.nanoTime(); boolean error = false; String reason = "ok"; TraceContext tc = null; if (clientConfig.isTraceEnable()){ tc = Tool.start(); } try { httpRequest.setURI(URI.create(url)); //request事件 client.onRequest(this); TraceContext child = tc == null ? null:tc.newChild(); if (child != null){ httpRequest.setHeader(clientConfig.getTraceId(), child.sn()); httpRequest.setHeader(clientConfig.getTraceOrder(), child.order()); } if (debug){ LOG.info(String.format("Request:%s",fullPath)); LOG.info("\tHeaders:"); HeaderIterator iter = httpRequest.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } CloseableHttpResponse resp = httpClient.execute(httpRequest); if (debug){ StatusLine status = resp.getStatusLine(); LOG.info(String.format("Response:%s-%s",status.getStatusCode(),status.getReasonPhrase())); LOG.info("\tHeaders:"); HeaderIterator iter = resp.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } HttpClientResponse response = new HttpClientResponse(resp,clientConfig.getEncoding()); //response事件 client.onResponse(response); return response; }catch (SocketTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1601",url, ex); }catch (ConnectTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1602",url, ex); }catch (ConnectException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1603",url, ex); }catch (NoHttpResponseException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1604",url, ex); }catch (Exception ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1004",url, ex); }finally{ if (clientConfig.isMetricsOutput()){ RemoteCallMetrics m = new RemoteCallMetrics(url); m.count(System.nanoTime() - start,error); Handler handler = RRDataHandlerFactory.getHandler(); if (handler != null){ handler.handle(m,System.currentTimeMillis()); } } if (clientConfig.isTraceEnable()){ Tool.end(tc, "Remote", url, error?"FAILED":"OK", reason); } } } @Override public Response execute(String fullPath,String rpcId) { String url = fullPath; long start = System.nanoTime(); boolean error = false; String reason = "ok"; TraceContext tc = null; if (clientConfig.isTraceEnable()){ tc = Tool.start(); } try { httpRequest.setURI(URI.create(url)); //request事件 client.onRequest(this); TraceContext child = tc == null ? null:tc.newChild(); if (child != null){ httpRequest.setHeader(clientConfig.getTraceId(), child.sn()); httpRequest.setHeader(clientConfig.getTraceOrder(), child.order()); } if (debug){ LOG.info(String.format("Request:%s",fullPath)); LOG.info("\tHeaders:"); HeaderIterator iter = httpRequest.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } CloseableHttpResponse resp = httpClient.execute(httpRequest); if (debug){ StatusLine status = resp.getStatusLine(); LOG.info(String.format("Response:%s-%s",status.getStatusCode(),status.getReasonPhrase())); LOG.info("\tHeaders:"); HeaderIterator iter = resp.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } HttpClientResponse response = new HttpClientResponse(resp,clientConfig.getEncoding()); //response事件 client.onResponse(response); return response; }catch (SocketTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1601",url, ex); }catch (ConnectTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1602",url, ex); }catch (ConnectException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1603",url, ex); }catch (NoHttpResponseException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1604",url, ex); }catch (Exception ex){ error = true; reason = ex.getMessage(); ex.printStackTrace(); throw new CallException("core.e1004",url, ex); }finally{ if (clientConfig.isMetricsOutput()){ RemoteCallMetrics m = new RemoteCallMetrics(url,rpcId); m.count(System.nanoTime() - start,error); Handler handler = RRDataHandlerFactory.getHandler(); if (handler != null){ handler.handle(m,System.currentTimeMillis()); } } if (clientConfig.isTraceEnable()){ Tool.end(tc, "Remote", url, error?"FAILED":"OK", reason); } } } public String getMetricsId(String id){ return String.format("rpc.thpt:%s",id); } protected Response execute(String path,Backend backend,String rpcId) { String url = client.getInvokeURL(backend, path); long start = System.nanoTime(); boolean error = false; String reason = "ok"; TraceContext tc = null; if (clientConfig.isTraceEnable()){ tc = Tool.start(); } try { httpRequest.setURI(URI.create(url)); //request事件 client.onRequest(this); TraceContext child = tc == null ? null:tc.newChild(); if (child != null){ httpRequest.setHeader(clientConfig.getTraceId(), child.sn()); httpRequest.setHeader(clientConfig.getTraceOrder(), child.order()); } if (debug){ LOG.info(String.format("Request:%s",url)); LOG.info("\tHeaders:"); HeaderIterator iter = httpRequest.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } CloseableHttpResponse resp = httpClient.execute(httpRequest); if (debug){ StatusLine status = resp.getStatusLine(); LOG.info(String.format("Response:%s-%s",status.getStatusCode(),status.getReasonPhrase())); LOG.info("\tHeaders:"); HeaderIterator iter = resp.headerIterator(); while (iter.hasNext()){ Header header = iter.nextHeader(); LOG.info(String.format("\t\t%s:%s",header.getName(),header.getValue())); } } HttpClientResponse response = new HttpClientResponse(resp,clientConfig.getEncoding()); //response事件 client.onResponse(response); return response; }catch (SocketTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1601",url, ex); }catch (ConnectTimeoutException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1602",url, ex); }catch (ConnectException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1603",url, ex); }catch (NoHttpResponseException ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1604",url, ex); }catch (Exception ex){ error = true; reason = ex.getMessage(); throw new CallException("core.e1004",url, ex); }finally{ if (clientConfig.isMetricsOutput()){ RemoteCallMetrics m = new RemoteCallMetrics(url,rpcId); m.count(System.nanoTime() - start,error); Handler handler = RRDataHandlerFactory.getHandler(); if (handler != null){ handler.handle(m,System.currentTimeMillis()); } } if (clientConfig.isTraceEnable()){ Tool.end(tc, "Remote", url, error?"FAILED":"OK", reason); } } } @Override public void close() { if (httpRequest != null){ httpRequest.releaseConnection(); } } public static class DirectOutputEntity extends AbstractHttpEntity{ protected DirectOutput out = null; public DirectOutputEntity(DirectOutput out){ this.out = out; } @Override public boolean isRepeatable() { return true; } @Override public long getContentLength() { // i don't know. return -1; } @Override public InputStream getContent() throws IOException, UnsupportedOperationException { throw new UnsupportedOperationException(); } @Override public void writeTo(OutputStream outstream) throws IOException { if (this.out != null){ this.out.writeTo(outstream); } } @Override public boolean isStreaming() { return false; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy