restemplate使用HttpClient发送请求绑定本地端口port(一)——单线程socket绑定本地端口

最近公司android项目处于维护阶段,开始做了一些java和运维的项目,也用nexus搭建公司的私服,好了,废话也不多说,开始今天的主题,怎么用HttpClient的请求框架绑定本地发送请求端口

我们都知道,网路简历连接,都离不开socket套接字,所以只有在这里我们才能设置好网路请求一些参数

写了一个小程序,试了一下绑定socket的本地端口

public void send(String ip,int port,String url,String sendData)
    {
        try {
            Socket socket = new Socket(ip, port,InetAddress.getByName("192.168.100.165"),10011);
            OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
            StringBuffer sb = new StringBuffer();
            //http协议中请求行
            sb.append("GET "+url+" HTTP/1.1\r\n");

            //http协议中请求头
            sb.append("Host: "+ip+"\r\n");
            sb.append("Connection: Keep-Alive\r\n");
            sb.append("user-agent: 1601\r\n");

            sb.append("\r\n");
            osw.write(sb.toString());
            osw.flush();

            //传回的消息的头信息
            InputStream is = socket.getInputStream();
            String line = null;
            int contentLength = 0;
            // 服务器发送过来的请求参数头部信息
            do {
                line = readLine(is, 0);
                //如果有Content-Length消息头时取出
                if (line.startsWith("Content-Length")) {
                    contentLength = Integer.parseInt(line.split(":")[1].trim());
                }
                //打印请求部信息
                System.out.print(line);
                //单独的回车换行,则表示请求头结束
            } while (!line.equals("\r\n"));
            System.out.print(readLine(is, contentLength));

            is.close();

        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String readLine(InputStream is, int contentLe) throws IOException {
        ArrayList lineByteList = new ArrayList();
        byte readByte;
        int total = 0;
        if (contentLe != 0) {
            do {
                readByte = (byte) is.read();
                lineByteList.add(Byte.valueOf(readByte));
                total++;
            } while (total < contentLe);//消息体读还未读完
        } else {
            do {
                readByte = (byte) is.read();
                lineByteList.add(Byte.valueOf(readByte));
            } while (readByte != 10);
        }

        byte[] tmpByteArr = new byte[lineByteList.size()];
        for (int i = 0; i < lineByteList.size(); i++) {
            tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
        }
        lineByteList.clear();

        return new String(tmpByteArr, encoding);
    }

    public static void main(String[] args) {
        SimpleHttpClient httpClient=new SimpleHttpClient();
        httpClient.send("61.135.169.121",
                443, "/index.php?tn=monline_3_dg",
                null);
    }

请求的是百度的地址,我们抓包看看,端口是真的绑定了

这里可以看到,发送的资源端口为10011,与上面绑定的恩地端口10011是一样的,为了防止是巧合,我们再请求两次

可以看到,端口确实是绑定了。

 

接下来,就是正式用到项目里面了

首先,我们来看一下公司直接的rest请求工具类RestTemplateUtil

@Component
public class RestTemplateUtil {

    private RestTemplate restTemplate;

    private RestTemplate httpsRestTemplate;

    private int timeout = 5000;

    private String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";

    private String APPLICATION_XML_UTF8 = "application/xml;charset=UTF-8";

    public RestTemplateUtil() {
        restTemplate = new RestTemplate();
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(timeout);
        requestFactory.setConnectTimeout(timeout);
        restTemplate.setRequestFactory(requestFactory);

        httpsRestTemplate = new RestTemplate();
        SimpleClientHttpRequestFactory requestFactoryHttps = new HttpsClientRequestFactory();
        requestFactoryHttps.setReadTimeout(timeout);
        requestFactoryHttps.setConnectTimeout(timeout);
        httpsRestTemplate.setRequestFactory(requestFactoryHttps);
    }

    private <T> T post(String url, String param, String mediaType, Class<T> bodyType) {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(mediaType);
        headers.setContentType(type);

        return exchange(url, param, HttpMethod.POST, bodyType, headers);
    }

    public <T> T postJson(String url, String param, Class<T> bodyType) {
        return post(url, param, APPLICATION_JSON_UTF8, bodyType);
    }

    public <T> T postXml(String url, String param, Class<T> bodyType) {
        return post(url, param, APPLICATION_XML_UTF8, bodyType);
    }

    public <T> T get(String url, String param, Class<T> bodyType) {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
        headers.setContentType(type);

        return exchange(url, param, HttpMethod.GET, bodyType, headers);

    }

    public <T> T put(String url, String data, Class<T> bodyType) {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
        headers.setContentType(type);

        return exchange(url, data, HttpMethod.PUT, bodyType, headers);
    }

    public <T> T delete(String url, String data, Class<T> bodyType) {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
        headers.setContentType(type);

        return exchange(url, data, HttpMethod.DELETE, bodyType, headers);
    }

    /**
     * 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题)
     *
     * @param url
     * @param content
     * @param method
     * @param bodyType
     * @param headers
     * @param <T>
     * @return
     */
    private <T> T exchange(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {

        // 发送请求
        HttpEntity<String> entity = new HttpEntity<>(content, headers);
        ResponseEntity<T> resultEntity = restTemplate.exchange(url, method, entity, bodyType);

        return resultEntity.getBody();
    }

    public <T> T convertToBean(Class<T> clz, String msg) {
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(clz);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            T t = (T) unmarshaller.unmarshal(new StringReader(msg));
            return t;
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String convertToXml(Object bean) {
        try {
            JAXBContext context = JAXBContext.newInstance(bean.getClass());
            Marshaller marshaller = context.createMarshaller();
            StringWriter writer = new StringWriter();
            marshaller.marshal(bean, writer);
            return writer.toString();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return null;
    }

    public <T> T httpsGet(String url, String param, Class<T> bodyType) {

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
        headers.setContentType(type);

        return exchangeHttps(url, param, HttpMethod.GET, bodyType, headers);

    }

    public <T> T httpsPost(String url, String param, Class<T> bodyType) {
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(APPLICATION_JSON_UTF8);
        headers.setContentType(type);
        return exchangeHttps(url,param,HttpMethod.POST,bodyType,headers);
    }

    private <T> T exchangeHttps(String url, String content, HttpMethod method, Class<T> bodyType, HttpHeaders headers) {

        // 发送请求
        HttpEntity<String> entity = new HttpEntity<>(content, headers);
        ResponseEntity<T> resultEntity = httpsRestTemplate.exchange(url, method, entity, bodyType);

        return resultEntity.getBody();
    }
}

可以看到,主要请求的配置还是在构造方法这里

public RestTemplateUtil() {
        restTemplate = new RestTemplate();
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(timeout);
        requestFactory.setConnectTimeout(timeout);
        restTemplate.setRequestFactory(requestFactory);

        httpsRestTemplate = new RestTemplate();
        SimpleClientHttpRequestFactory requestFactoryHttps = new HttpsClientRequestFactory();
        requestFactoryHttps.setReadTimeout(timeout);
        requestFactoryHttps.setConnectTimeout(timeout);
        httpsRestTemplate.setRequestFactory(requestFactoryHttps);
    }

这里新建了两个ResTemplate对象,一个是用于http请求,一个则是用于https请求

主要注意这两个地方,一个是http请求的请求工厂类SimpleClientHttpRequestFactory,还有一个则是https请求工厂类HttpsClientRequestFactory,可以看出来https请求工厂类是继承SimpleClientHttpRequestFactory的,这里spring框架中的restemplate类,在初始化的时候都需要传入一个请求工厂来管理请求,那我们要控制端口,就只能从这个请求工厂类着手了

看一下传入的工厂是个什么东西

	/**
	 * Set the request factory that this accessor uses for obtaining client request handles.
	 * <p>The default is a {@link SimpleClientHttpRequestFactory} based on the JDK's own
	 * HTTP libraries ({@link java.net.HttpURLConnection}).
	 * <p><b>Note that the standard JDK HTTP library does not support the HTTP PATCH method.
	 * Configure the Apache HttpComponents or OkHttp request factory to enable PATCH.</b>
	 * @see #createRequest(URI, HttpMethod)
	 * @see org.springframework.http.client.HttpComponentsAsyncClientHttpRequestFactory
	 * @see org.springframework.http.client.OkHttp3ClientHttpRequestFactory
	 */
	public void setRequestFactory(ClientHttpRequestFactory requestFactory) {
		Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
		this.requestFactory = requestFactory;
	}

点进方法,可以打看到传入的ClientHttpRequestFactory一个类,这是个接口,再看一下他的实现

可以看到,所有的实现类都必须实现

ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException;

这个接口,用来创建请求

在实现类里面:

SimpleClientHttpRequestFactory,请求是用是的java自带的网络请求框架,而且它也只有一个集成类,就是那个https请求的工厂类HttpsClientRequestFactory

	@Override
	public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
		HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
		prepareConnection(connection, httpMethod.name());

		if (this.bufferRequestBody) {
			return new SimpleBufferingClientHttpRequest(connection, this.outputStreaming);
		}
		else {
			return new SimpleStreamingClientHttpRequest(connection, this.chunkSize, this.outputStreaming);
		}
	}

我们看这个方法里面,创建的HttpURConnection对象,就是java.net包下的,好了,这个不是重点

里面我们还可以看到有okhttp和okhttp3的工厂类,这些都是用okhttp的网络请求框架来来实现的rest请求,因为没有导okhttp的包,所以源码进去会报错,时间原因,我也没有深究这个了

接下来,重点来了

HttpComponentsClientHttpRequestFactory请求工厂,使用的是HttpClient网络请求框架

注意这需要自己添加HttpClient相关的依赖包,我用的是这个

    compile group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.4.1'
    compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.1'

看看这个类

 

	/**
	 * Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
	 * with a default {@link HttpClient}.
	 */
	public HttpComponentsClientHttpRequestFactory() {
		this.httpClient = HttpClients.createSystem();
	}

	/**
	 * Create a new instance of the {@code HttpComponentsClientHttpRequestFactory}
	 * with the given {@link HttpClient} instance.
	 * @param httpClient the HttpClient instance to use for this request factory
	 */
	public HttpComponentsClientHttpRequestFactory(HttpClient httpClient) {
		setHttpClient(httpClient);
	}

可以看到构造函数有两个,一个无参构造,另一个是有参,可以传入一个HttpClient的对象,既然要自定义,那肯定是选择第二个构造来创建这个对象咯

接下来就是这么写这个HttpClient实例了

public interface HttpClient {
  

看,这是个接口,看看无参是这么创建的实例

this.httpClient = HttpClients.createSystem();

用的是一个HttpCliens类来创建的实例对象,再去看看HttpClients

@Immutable
public class HttpClients {

    private HttpClients() {
        super();
    }

    /**
     * Creates builder object for construction of custom
     * {@link CloseableHttpClient} instances.
     */
    public static HttpClientBuilder custom() {
        return HttpClientBuilder.create();
    }

    /**
     * Creates {@link CloseableHttpClient} instance with default
     * configuration.
     */
    public static CloseableHttpClient createDefault() {
        return HttpClientBuilder.create().build();
    }

    /**
     * Creates {@link CloseableHttpClient} instance with default
     * configuration based on ssytem properties.
     */
    public static CloseableHttpClient createSystem() {
        return HttpClientBuilder.create().useSystemProperties().build();
    }

    /**
     * Creates {@link CloseableHttpClient} instance that implements
     * the most basic HTTP protocol support.
     */
    public static CloseableHttpClient createMinimal() {
        return new MinimalHttpClient(new PoolingHttpClientConnectionManager());
    }

    /**
     * Creates {@link CloseableHttpClient} instance that implements
     * the most basic HTTP protocol support.
     */
    public static CloseableHttpClient createMinimal(final HttpClientConnectionManager connManager) {
        return new MinimalHttpClient(connManager);
    }

}

可以看到,调用的是HttpClientBuilder的类创建实例,useSystemProperties()方法只是设置一个配置参数

/**
 * Use system properties when creating and configuring default
 * implementations.
 */
public final HttpClientBuilder useSystemProperties() {
    this.systemProperties = true;
    return this;
}

是否为系统配置参数,在创建实例的时候会用到,主要是build()方法,我们进去看看

   public CloseableHttpClient build() {
        // Create main request executor
        // We copy the instance fields to avoid changing them, and rename to avoid accidental use of the wrong version
        PublicSuffixMatcher publicSuffixMatcherCopy = this.publicSuffixMatcher;
        if (publicSuffixMatcherCopy == null) {
            publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();
        }

        HttpRequestExecutor requestExecCopy = this.requestExec;
        if (requestExecCopy == null) {
            requestExecCopy = new HttpRequestExecutor();
        }
        HttpClientConnectionManager connManagerCopy = this.connManager;
        if (connManagerCopy == null) {
            LayeredConnectionSocketFactory sslSocketFactoryCopy = this.sslSocketFactory;
            if (sslSocketFactoryCopy == null) {
                final String[] supportedProtocols = systemProperties ? split(
                        System.getProperty("https.protocols")) : null;
                final String[] supportedCipherSuites = systemProperties ? split(
                        System.getProperty("https.cipherSuites")) : null;
                HostnameVerifier hostnameVerifierCopy = this.hostnameVerifier;
                if (hostnameVerifierCopy == null) {
                    hostnameVerifierCopy = new DefaultHostnameVerifier(publicSuffixMatcherCopy);
                }
                if (sslContext != null) {
                    sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                            sslContext, supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                } else {
                    if (systemProperties) {
                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                (SSLSocketFactory) SSLSocketFactory.getDefault(),
                                supportedProtocols, supportedCipherSuites, hostnameVerifierCopy);
                    } else {
                        sslSocketFactoryCopy = new SSLConnectionSocketFactory(
                                SSLContexts.createDefault(),
                                hostnameVerifierCopy);
                    }
                }
            }
            @SuppressWarnings("resource")
            final PoolingHttpClientConnectionManager poolingmgr = new PoolingHttpClientConnectionManager(
                    RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.getSocketFactory())
                        .register("https", sslSocketFactoryCopy)
                        .build(),
                    null,
                    null,
                    null,
                    connTimeToLive,
                    connTimeToLiveTimeUnit != null ? connTimeToLiveTimeUnit : TimeUnit.MILLISECONDS);
            if (defaultSocketConfig != null) {
                poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
            }
            if (defaultConnectionConfig != null) {
                poolingmgr.setDefaultConnectionConfig(defaultConnectionConfig);
            }
            if (systemProperties) {
                String s = System.getProperty("http.keepAlive", "true");
                if ("true".equalsIgnoreCase(s)) {
                    s = System.getProperty("http.maxConnections", "5");
                    final int max = Integer.parseInt(s);
                    poolingmgr.setDefaultMaxPerRoute(max);
                    poolingmgr.setMaxTotal(2 * max);
                }
            }
            if (maxConnTotal > 0) {
                poolingmgr.setMaxTotal(maxConnTotal);
            }
            if (maxConnPerRoute > 0) {
                poolingmgr.setDefaultMaxPerRoute(maxConnPerRoute);
            }
            connManagerCopy = poolingmgr;
        }
        ConnectionReuseStrategy reuseStrategyCopy = this.reuseStrategy;
        if (reuseStrategyCopy == null) {
            if (systemProperties) {
                final String s = System.getProperty("http.keepAlive", "true");
                if ("true".equalsIgnoreCase(s)) {
                    reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
                } else {
                    reuseStrategyCopy = NoConnectionReuseStrategy.INSTANCE;
                }
            } else {
                reuseStrategyCopy = DefaultConnectionReuseStrategy.INSTANCE;
            }
        }
        ConnectionKeepAliveStrategy keepAliveStrategyCopy = this.keepAliveStrategy;
        if (keepAliveStrategyCopy == null) {
            keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;
        }
        AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
        if (targetAuthStrategyCopy == null) {
            targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;
        }
        AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
        if (proxyAuthStrategyCopy == null) {
            proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;
        }
        UserTokenHandler userTokenHandlerCopy = this.userTokenHandler;
        if (userTokenHandlerCopy == null) {
            if (!connectionStateDisabled) {
                userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;
            } else {
                userTokenHandlerCopy = NoopUserTokenHandler.INSTANCE;
            }
        }

        String userAgentCopy = this.userAgent;
        if (userAgentCopy == null) {
            if (systemProperties) {
                userAgentCopy = System.getProperty("http.agent");
            }
            if (userAgentCopy == null) {
                userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient",
                        "org.apache.http.client", getClass());
            }
        }

        ClientExecChain execChain = createMainExec(
                requestExecCopy,
                connManagerCopy,
                reuseStrategyCopy,
                keepAliveStrategyCopy,
                new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
                targetAuthStrategyCopy,
                proxyAuthStrategyCopy,
                userTokenHandlerCopy);

        execChain = decorateMainExec(execChain);

        HttpProcessor httpprocessorCopy = this.httpprocessor;
        if (httpprocessorCopy == null) {

            final HttpProcessorBuilder b = HttpProcessorBuilder.create();
            if (requestFirst != null) {
                for (final HttpRequestInterceptor i: requestFirst) {
                    b.addFirst(i);
                }
            }
            if (responseFirst != null) {
                for (final HttpResponseInterceptor i: responseFirst) {
                    b.addFirst(i);
                }
            }
            b.addAll(
                    new RequestDefaultHeaders(defaultHeaders),
                    new RequestContent(),
                    new RequestTargetHost(),
                    new RequestClientConnControl(),
                    new RequestUserAgent(userAgentCopy),
                    new RequestExpectContinue());
            if (!cookieManagementDisabled) {
                b.add(new RequestAddCookies());
            }
            if (!contentCompressionDisabled) {
                if (contentDec
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值