发起http请求的几种方式

日常开发中,无论是内部服务之间的调用,还是第三方服务,都免不了发起http请求。Java中常见的http请求方式大致有原生的HttpURLConnection、Apache的HttpClient、Spring的RestTemplate等。

1、HttpURLConnection方式

get请求

public static void main(String[] args) {
        try {
            // 1. 得到访问地址的URL
            URL url = new URL("http://localhost:8080/index.html");
            // 2. 得到网络访问对象java.net.HttpURLConnection
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            /* 3. 设置请求参数(过期时间,输入、输出流、访问方式),以流的形式进行连接 */
            // 设置是否向HttpURLConnection输出
            connection.setDoOutput(false);
            // 设置是否从HttpUrlConnection读入
            connection.setDoInput(true);
            // 设置请求方式("GET"/"POST")
            connection.setRequestMethod("GET");
            // 设置是否使用缓存
            connection.setUseCaches(true);
            // 设置此 HttpURLConnection 实例是否应该自动执行 HTTP 重定向
            connection.setInstanceFollowRedirects(true);
            // 设置超时时间
            connection.setConnectTimeout(3000);
            // 连接
            connection.connect();
            // 4. 得到响应状态码的返回值 responseCode
            int code = connection.getResponseCode();
            // 5. 如果返回值正常,数据在网络中是以流的形式得到服务端返回的数据
            String msg = "";
            if (code == 200) { // 正常响应
                // 从流中读取响应信息
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line = null;
                while ((line = reader.readLine()) != null) { // 循环从流中读取
                    msg += line + "\n";
                }
                reader.close(); // 关闭流
            }
            // 6. 断开连接,释放资源
            connection.disconnect();

            // 显示响应结果
            System.out.println(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

post请求

public static void main(String[] args) {
        try {
            // 1. 获取访问地址URL
            URL url = new URL("http://localhost:8080/index.jsp");
            // 2. 创建HttpURLConnection对象
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            /* 3. 设置请求参数等 */
            // 请求方式
            connection.setRequestMethod("POST");
            // 设置连接超时时间
            connection.setConnectTimeout(3000);
        // 设置是否向 HttpUrlConnection 输出,对于post请求,参数要放在 http 正文内,因此需要设为true,默认为false。
            connection.setDoOutput(true);
            // 设置是否从 HttpUrlConnection读入,默认为true
            connection.setDoInput(true);
            // 设置是否使用缓存
            connection.setUseCaches(false);
            // 设置此 HttpURLConnection 实例是否应该自动执行 HTTP 重定向
            connection.setInstanceFollowRedirects(true);
            // 设置使用标准编码格式编码参数的名-值对
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        // 添加 HTTP HEAD 中的一些参数。
        // JDK8中,HttpURLConnection默认开启Keep-Alive
       // connection.setRequestProperty("Connection", "Keep-Alive");
            // 连接
            connection.connect();
            /* 4. 处理输入输出 */
            // 写入参数到请求中
            String params = "username=test&password=123456";
            OutputStream out = connection.getOutputStream();
            out.write(params.getBytes());
            out.flush();
            out.close();
            // 从连接中读取响应信息
            String msg = "";
            int code = connection.getResponseCode();
            if (code == 200) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                while ((line = reader.readLine()) != null) {
                    msg += line + "\n";
                }
                reader.close();
            }
            // 5. 断开连接
            connection.disconnect();

            // 处理结果
            System.out.println(msg);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2、HttpClient方式

get请求

public String get(JSONObject parameters, String url) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        if (parameters != null) {
            StringBuffer query = new StringBuffer();
            int i = 0;
            for (String key : parameters.keySet()) {
                if (i == 0) {
                   query.append("?");
                }
                query.append( key + "=" + parameters.getString(key) + "&");
                i++;
            }
            if (query.length() > 0) {
                query.deleteCharAt(query.length() -1);
            }
            url = url + query;
        }
        HttpGet method = new HttpGet(url);
        String body = null;

        if (method != null & parameters != null) {
            try {
                // 建立一个NameValuePair数组,用于存储欲传送的参数
                method.addHeader("Content-type", "application/json; charset=utf-8");
                method.setHeader("Accept", "application/json");
                CloseableHttpResponse response = httpClient.execute(method);
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode != HttpStatus.SC_OK) {
                    System.out.println("调用失败:" + response.getStatusLine());
                }

                // Read the response body
                body = EntityUtils.toString(response.getEntity());
                response.close();
                httpClient.close();
            } catch (IOException e) {
                // 网络错误
                e.printStackTrace();
            }
        }
        return body;
    }

post请求

public static void main(JSONObject parameters , String url ){
        CloseableHttpClient httpClient = createSSLClientDefault();
        //get类型的请求
        HttpGet method = new HttpGet(uriBuilder.build());
        //post类型的请求
        HttpPost method = new HttpPost(url);
        method.setHeader("Accept", "application/json");
        String body = null;
        if ( parameters != null) {
            try {
                method.addHeader("Content-type", "application/json; charset=utf-8");
                method.setEntity(new StringEntity(parameters.toString(), Charset.forName("UTF-8")));
                CloseableHttpResponse response = httpClient.execute(method);
                int statusCode = response.getStatusLine().getStatusCode();

                if (statusCode != HttpStatus.SC_OK) {
                    HttpEntity httpEntity = response.getEntity();
                    String jsObject = EntityUtils.toString(httpEntity, "UTF-8");
                    System.out.println("调用失败:" + response.getStatusLine());
                    System.out.println("调用失败:" + jsObject);
                    return null;
                }
                // Read the response body
                body = EntityUtils.toString(response.getEntity());
                response.close();
                httpClient.close();
            } catch (IOException e) {
                // 网络错误
                e.printStackTrace();
            }
        }
        return body;

    }


//解决https访问失败的情况
public static CloseableHttpClient createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 信任所有
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            return HttpClients.custom().setSSLSocketFactory(sslsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();

    }

3、RestTemplate方式

如果是基于Spring框架,那么强烈推荐使用这种方式。优势:只需要关心具体的URL、header、body等,其他细节不必关心,都已经封装好了。只需要使用RestTemplate.exchange就可以了,它支持GET、POST、PUT、DELETE等

1)配置和使用

创建RestTemplate,只需要把RestTemplate注入到bean里面

@Configuration
public class RestTempleConfig {
    
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

在工程中,常用的方式是扩展做成一个工具类,且能支持https

@Configuration
public class RestTemple {

    @Bean
    public RestTemplate httpsRestTemplate(HttpComponentsClientHttpRequestFactory httpsFactory){
        RestTemplate restTemplate = new RestTemplate(httpsFactory);
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse clientHttpResponse) {
                //默认处理非200的返回,会抛异常
            }
        });
        return restTemplate;
    }

    @Bean(name = "httpsFactory")
    public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws Exception{
        CloseableHttpClient httpClient = HttpsClientUtils.acceptsUntrustedCertsHttpClient();
        HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpsFactory.setReadTimeout(2000);
        httpsFactory.setConnectTimeout(2000);
        return httpsFactory;
    }


    public  <T> String httpRequest(String url, HttpMethod method, HttpEntity<T> entity){
        try {
            //发起一个POST请求
            ResponseEntity<String> result = httpsRestTemplate(httpComponentsClientHttpRequestFactory()).exchange(url, method, entity, String.class);
            return result.getBody();
        } catch (Exception e) {
            System.out.println("请求失败: " + e.getMessage());
        }
        return null;
    }

}

支持https的类:

public class HttpsClientUtils {
/*
* https ip地址请求忽略证书设置
*
* */
    public static CloseableHttpClient acceptsUntrustedCertsHttpClient() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        HttpClientBuilder b = HttpClientBuilder.create();

        // setup a Trust Strategy that allows all certificates.
        //
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                return true;
            }
        }).build();
        b.setSSLContext(sslContext);

        // don't check Hostnames, either.
        //      -- use SSLConnectionSocketFactory.getDefaultHostnameVerifier(), if you don't want to weaken
        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;

        // here's the special part:
        //      -- need to create an SSL Socket Factory, to use our weakened "trust strategy";
        //      -- and create a Registry, to register it.
        //
        SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        Registry socketFactoryRegistry = RegistryBuilder.create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslSocketFactory)
                .build();

        // now, we create connection-manager using our Registry.
        //      -- allows multi-threaded use
        PoolingHttpClientConnectionManager connMgr = new PoolingHttpClientConnectionManager( socketFactoryRegistry);
        connMgr.setMaxTotal(200);
        connMgr.setDefaultMaxPerRoute(100);
        b.setConnectionManager( connMgr);

        // finally, build the HttpClient;
        //      -- done!
        CloseableHttpClient client = b.build();

        return client;
    }

}

使用: 

@Autowired
RestTemple restTemple;

public void test(){
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-type","application/x-www-form-urlencoded; charset=UTF-8");
        headers.set("Accept", "application/json, text/plain, */*");
        JSONObject js = JSONObject.parseObject(unVar);
        js.put("key","value");
        //设置访问的Entity
        HttpEntity entity = new HttpEntity<>(js.toString(), headers);
        String result = restTemple.httpRequest(urlLogin, HttpMethod.POST, entity);

}

2)多个请求之间传递cookie

如果多个请求之间需要传递cookie参数,如何处理呢?

可以在RestTemle类中增加一个getCookie函数,返回cookie的值

@Configuration
public class RestTemple {
    public  List<String> getCookie(String url, HttpMethod method, HttpEntity<String> entity){
        try {
            //发起一个POST请求
            ResponseEntity<String> result = httpsRestTemplate(httpComponentsClientHttpRequestFactory()).exchange(url, method, entity, String.class);
            return result.getHeaders().get("Set-Cookie");
        } catch (Exception e) {
            System.out.println("请求失败: " + e.getMessage());
        }
        return null;
    }

    public  <T> String httpRequest(String url, HttpMethod method, HttpEntity<T> entity){
        try {
            //发起一个POST请求
            ResponseEntity<String> result = httpsRestTemplate(httpComponentsClientHttpRequestFactory()).exchange(url, method, entity, String.class);
            return result.getBody();
        } catch (Exception e) {
            System.out.println("请求失败: " + e.getMessage());
        }
        return null;
    }
}

然后在使用时将cookie传入heads中:

public void test(){
    List cookies = login();
    addInfo(cookies);
}

public List login(){
    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept", "application/json, text/plain, */*");
    String params = "admin";
    HttpEntity entity = new HttpEntity<>(params, headers);
    List cookies = restTemple.getCookie(urlCreateLogin, HttpMethod.POST, entity);
    return cookies;
}

public void addInfo(List cookies){
    JSONObject js = new JSONObject();
    js.put("key","value");
    HttpHeaders headers = new HttpHeaders();
    //把cookies设到headers中
    headers.put(HttpHeaders.COOKIE, cookies);
    HttpEntity entity = new HttpEntity<>(js.toString(), headers);
    String result = restTemple.httpRequest(urlAdd, HttpMethod.POST, entity);
    System.out.println(result);
}

附:RestTemplate架构图

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值