最近做小程序接入微信支付的模块,涉及到了springboot后台处理数据后向微信的jsapi统一下单网址发送请求获得返回数据这种模式。那么如何用java语言获取一个客户端连接并将请求执行在客户端上呢?这里就得用到HttpClient这个客户端连接对象了。看看它的源码:
- public interface HttpClient {
- /** @deprecated */
- @Deprecated
- HttpParams getParams();
-
- /** @deprecated */
- @Deprecated
- ClientConnectionManager getConnectionManager();
-
- HttpResponse execute(HttpUriRequest var1) throws IOException, ClientProtocolException;
-
- HttpResponse execute(HttpUriRequest var1, HttpContext var2) throws IOException, ClientProtocolException;
-
- HttpResponse execute(HttpHost var1, HttpRequest var2) throws IOException, ClientProtocolException;
-
- HttpResponse execute(HttpHost var1, HttpRequest var2, HttpContext var3) throws IOException, ClientProtocolException;
-
-
T execute(HttpUriRequest var1, ResponseHandler extends T> var2) throws IOException, ClientProtocolException; -
-
T execute(HttpUriRequest var1, ResponseHandler extends T> var2, HttpContext var3) throws IOException, ClientProtocolException; -
-
T execute(HttpHost var1, HttpRequest var2, ResponseHandler extends T> var3) throws IOException, ClientProtocolException; -
-
T execute(HttpHost var1, HttpRequest var2, ResponseHandler extends T> var3, HttpContext var4) throws IOException, ClientProtocolException; - }
可以看到执行某一网络请求的参数是以请求或者是主机。返回的结果都是HttpResponse类型。泛型暂不考虑。
来看看HttpResponse的源码:
- public interface HttpResponse extends HttpMessage {
- StatusLine getStatusLine();
-
- void setStatusLine(StatusLine var1);
-
- void setStatusLine(ProtocolVersion var1, int var2);
-
- void setStatusLine(ProtocolVersion var1, int var2, String var3);
-
- void setStatusCode(int var1) throws IllegalStateException;
-
- void setReasonPhrase(String var1) throws IllegalStateException;
-
- HttpEntity getEntity();
-
- void setEntity(HttpEntity var1);
-
- Locale getLocale();
-
- void setLocale(Locale var1);
- }
可以发现都是一些可修改的方法与获取数据的方法,这里我们主要关注的方法是 HttpEntity getEntity();我们用它来获取响应的数据,再结合自身的业务对数据进行处理(我们在HttpMessage这个实体类插个眼)。
我们这就需要回过头找到httpclient对象执行方法里的httpurirequest类型是个什么东西了?
- public abstract class HttpRequestBase extends AbstractExecutionAwareRequest implements HttpUriRequest, Configurable {
- private ProtocolVersion version;
- private URI uri;
- private RequestConfig config;
-
- public HttpRequestBase() {
- }
- ...........
- }
而这个实现了接口HttpUriRequest的抽象类HTTPRequestBase(我们在他实现的第二个接口Configurable这里插个眼,待会还会说它)向下有子类HttpGet来继承实现:
- public class HttpGet extends HttpRequestBase {
- public static final String METHOD_NAME = "GET";
-
- public HttpGet() {
- }
-
- public HttpGet(URI uri) {
- this.setURI(uri);
- }
-
- public HttpGet(String uri) {
- this.setURI(URI.create(uri));
- }
-
- public String getMethod() {
- return "GET";
- }
- }
这是不是就清晰多了?先创建一个HttpClient对象,再创建一个HTTPGet或者是HttpPost对象,向内注入String类型的Url网址,调用HTTPClient的execute方法将请求对象导入进去就可以实现网址的访问。
那么请求的属性怎么办?比如请求超时时间呀等等,我们这样简单的实现是不能去配置请求的属性的,这个时候我们就要回去看看我们插的眼了!
Configurable 源码:
- public interface Configurable {
- RequestConfig getConfig();
- }
可以发现它有一个方法,返回的类型是RequestConfig这个词的中文意思很简单,请求配置:向下找找RequestConfig类的源码来看(源码太多,我只粘了一部分):
- public class RequestConfig implements Cloneable {
- public static final RequestConfig DEFAULT = (new RequestConfig.Builder()).build();
- private final boolean expectContinueEnabled;
- private final HttpHost proxy;
- private final InetAddress localAddress;
- private final boolean staleConnectionCheckEnabled;
- private final String cookieSpec;
- private final boolean redirectsEnabled;
- private final boolean relativeRedirectsAllowed;
- private final boolean circularRedirectsAllowed;
- private final int maxRedirects;
- private final boolean authenticationEnabled;
- private final Collection
targetPreferredAuthSchemes; - private final Collection
proxyPreferredAuthSchemes; - private final int connectionRequestTimeout;
- private final int connectTimeout;
- private final int socketTimeout;
- private final boolean contentCompressionEnabled;
- private final boolean normalizeUri;
-
- protected RequestConfig() {
- this(false, (HttpHost)null, (InetAddress)null, false, (String)null, false, false, false, 0, false, (Collection)null, (Collection)null, 0, 0, 0, true, true);
- }
-
- RequestConfig(boolean expectContinueEnabled, HttpHost proxy, InetAddress localAddress, boolean staleConnectionCheckEnabled, String cookieSpec, boolean redirectsEnabled, boolean relativeRedirectsAllowed, boolean circularRedirectsAllowed, int maxRedirects, boolean authenticationEnabled, Collection
targetPreferredAuthSchemes, Collection proxyPreferredAuthSchemes, int connectionRequestTimeout, int connectTimeout, int socketTimeout, boolean contentCompressionEnabled, boolean normalizeUri) { - this.expectContinueEnabled = expectContinueEnabled;
- this.proxy = proxy;
- this.localAddress = localAddress;
- this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
- this.cookieSpec = cookieSpec;
- this.redirectsEnabled = redirectsEnabled;
- this.relativeRedirectsAllowed = relativeRedirectsAllowed;
- this.circularRedirectsAllowed = circularRedirectsAllowed;
- this.maxRedirects = maxRedirects;
- this.authenticationEnabled = authenticationEnabled;
- this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
- this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
- this.connectionRequestTimeout = connectionRequestTimeout;
- this.connectTimeout = connectTimeout;
- this.socketTimeout = socketTimeout;
- this.contentCompressionEnabled = contentCompressionEnabled;
- this.normalizeUri = normalizeUri;
- }
-
- public boolean isExpectContinueEnabled() {
- return this.expectContinueEnabled;
- }
-
- public HttpHost getProxy() {
- return this.proxy;
- }
-
- public InetAddress getLocalAddress() {
- return this.localAddress;
- }
- .............
- }
可以发现里面还是有很多常见的属性配置的,套接字超时,请求超时时间等等,以及代理的配置。
那么问题又来了,配置请求头参数呢?回去找我们插的第一个眼HttpMessage对象:
- public interface HttpMessage {
- ProtocolVersion getProtocolVersion();
-
- boolean containsHeader(String var1);
-
- Header[] getHeaders(String var1);
-
- Header getFirstHeader(String var1);
-
- Header getLastHeader(String var1);
-
- Header[] getAllHeaders();
-
- void addHeader(Header var1);
-
- void addHeader(String var1, String var2);
-
- void setHeader(Header var1);
-
- void setHeader(String var1, String var2);
-
- void setHeaders(Header[] var1);
-
- void removeHeader(Header var1);
-
- void removeHeaders(String var1);
-
- HeaderIterator headerIterator();
-
- HeaderIterator headerIterator(String var1);
- ...............
- }
-
我们可以发现它是可以对请求的头进行增加和删除的!那么是不是就可以实战测试一下去?
下面是我自己测试去百度的源码:
- @RequestMapping("/httpTest")
- @ResponseBody
- public String HttpClientTest(){
- //百度访问不会给返回值,因为是一个页面且不做参数处理,连接会一直保持,你可以更换网址去查看返回数据。
- String Url = "http://www.baidu.com";
- BasicHttpClientConnectionManager connectionManager;
- connectionManager = new BasicHttpClientConnectionManager(
- RegistryBuilder.
create(). - register("http", PlainConnectionSocketFactory.getSocketFactory())
- .register("https", SSLConnectionSocketFactory.getSocketFactory())
- .build(),null,null,null
- );
- CloseableHttpClient httpClient = HttpClientBuilder.create().
- setConnectionManager(connectionManager)
- .build();
- HttpGet httpGet = new HttpGet(Url);
- try {
- HttpResponse httpResponse = httpClient.execute(httpGet);
- HttpEntity entity = httpResponse.getEntity();
- return EntityUtils.toString(entity,"UTF-8");
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return "ERROR-404-NETREQUEST";
- }
效果图我挂一个将访问URL更改成带有返回数据的效果图给大家:
至于这个ip就是本机的私网ip,和你们的localhost没区别都是挂在本机访问,但是出内网可不是由这个ip出去的,路由器会将私网与公网ip之间实现转换的。8081是我springboot启动的端口。