最近比较忙碌,都没有时间更新公众号文章,表示比较惭愧。最近翻看了一下自己的博客,发现这篇文章的内容还是挺实用,所以,想分享给大家,欢迎阅读。在后续,我会从一个范围的角度进行编写一系列文章,便于各位深层次的理解,而不是片面的了解知识点,并且会有规律性的更新文章,期望你的持续关注。
另外,我也官宣一下自己的花名为【小蜗牛】,愿我们都能像小蜗牛一样,一步一个脚印,坚持不懈,达到我们的梦想彼岸。
情景引入
旁白:
今天兴致极好,开开心心的与小白玩着“网页小游戏”
1.小白
真开心呀,好久没有玩这些网页游戏了呢。
2.小蜗牛
确实,工作一来,哪有这样的闲情逸致。
1.小白
不过,你看,咱们玩的游戏都是通过网页链接请求,然后返回给咱们这么多对应的响应内容,它这里感觉好神奇。2.小蜗牛
当然,它里面涉及到的内容还是非常多,可不是一下就能完整掌握的,你这思考问题的能力大大加强了嘛!
1.小白
这可不嘛,学习到老才行呢。不过,我经常听到同事说,快给我一个接口地址,我要向你发出请求获取信息啦,这里面到底是怎么实现的,一直都没有机会去请教他们。2.小蜗牛
虚心求教,这是非常值得的,不要害怕,不懂就要问,这才是应该有的态度。既然,这样的话,那我就给你科普科普。这不,正好咱们也可以“中场休息”一会,再继续游戏呢。
1.小白
好呀好呀!学习,游戏两不误,岂不是人生一大快事!2.小蜗牛
小白,你已经长大了!!
引言
当我们输入一个URL然后回车,页面会显示出对应的功能信息,那么它这个过程到底是如何的呢?其实,这里面涉及到的内容会非常多,比如缓存,地址解析,http协议,网络请求,OSI模型,服务器数据组装,页面渲染等等。这里,就不会说得那么详细(PS:但是这个链路过程,建议各位看官可以好好的琢磨琢磨,分析分析),本文主要是针对,如果对一个已知URL发出请求并获取到其实时的响应信息;
实际场景
我想,在实际开发中经常会碰到这样的事情,就是:需要Http请求其他同事开发的接口,而获取对应需要的内容,比如下载一个URL的文件或者获取数据列表信息等等以及调用第三方公共接口信息。那么,必不可少的就是通过代码去发出一个http的请求。那么,具体如何操作呢?客观,慢慢往下看!
操作方法
现在的方法有很多,且不限于本文说到的几种方式哦!本文主要采取循序渐进的方式,并没有说哪一种方法就是最好的,具体问题具体分析,要以一种开放的心态看待这个问题。
HttpUrlConnection
请求步骤
PS:该方式是最原始的方式,所以值得学习其内部执行流程;
package com.hnu.scw.utils;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;/** * @ Author :scw * @ Date :Created in 上午 10:34 2020/5/24 0024 * @ Description:请求URL的post方法工具类 * @ Modified By: * @Version: $version$ */public class HttpPostUtils { /** * 请求URL的post请求 * @param url 请求url地址 * @param parameters 请求参数 * @return 响应结果字符串 * @throws Exception 异常信息 */ public static String doRequestPostMethod(String url, Map<String, Object> parameters) throws Exception { // 将参数转为String(PS:因为如果URL需要参数的话,那么都是采取字符串字节的形式) String params = convertRequestParameter(parameters); URL restURL = new URL(url); // 请求失败的次数(PS:便于减少由于某次的网络抖动而影响请求) int errorNumber = 0; while( errorNumber < 3 ) { try { HttpURLConnection conn = (HttpURLConnection) restURL.openConnection(); // 设置请求超时时间(PS:可以不设置) conn.setConnectTimeout(5000); conn.setReadTimeout(5000); // 请求方式(PS:这里采取POST请求,如果需要GET请求,则为GET) conn.setRequestMethod("POST"); // 设置请求的数据格式为JSON conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); conn.setRequestProperty("Connection", "Keep-Alive"); // 是否从httpUrlConnection读入,默认情况下是true conn.setDoOutput(true); // 是否允许用户交互,假设为true,则允许用户交互的上下文中对此URL进行检查(比如对话框验证交互)。 conn.setAllowUserInteraction(false); // 获取输出流(PS:这里方式很多,这里提供几种) // 方式一 PrintStream ps = new PrintStream(conn.getOutputStream()); ps.print(params); ps.close(); // 方式二 /* DataOutputStream out = new DataOutputStream(conn.getOutputStream()); out.write(params.getBytes("UTF-8")); out.flush(); out.close();*/ // 建立连接 conn.connect(); // 获取响应输入流 BufferedReader bReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; String resultStr = ""; // 拼接响应内容 while (null != (line = bReader.readLine())) { resultStr += line; } bReader.close(); // 返回相应结果(PS:为字符串格式) return resultStr; } catch (Exception e) { // 错误次数+1 errorNumber++; } } throw new Exception("当前网络异常存在抖动,请稍后再试"); } /** * 将map形式的参数转为字符串形式 * @param parameters 请求参数 * @return 请求参数字符串 */ private static String convertRequestParameter(Map<String, Object> parameters) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); // 遍历接参数内容 for (Map.Entry<String,Object> param : parameters.entrySet()) { if (sb.length() != 0) { sb.append('&'); } // 防止中文乱码 sb.append(URLEncoder.encode(param.getKey(), "UTF-8")); sb.append('='); sb.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8")); } return sb.toString(); }}
OkHttpClient
添加依赖
<dependency> <groupId>com.squareup.okhttp3groupId> <artifactId>okhttpartifactId> <version>3.8.0version> dependency>
请求步骤(GET和POST方式)
package com.hnu.scw.utils;import okhttp3.*;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.SSLSession;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;/** * @ Author :scw * @ Date :Created in 上午 10:34 2020/5/24 0024 * @ Description:请求URL的post方法工具类 * @ Modified By: * @Version: $version$ */public class HttpPostUtils { /** * 执行 POST 请求 * @param url 请求的URL * @return 响应结果 */ public String doRequestPostByOkHttpClient(String url) { // ssl的认证重写(PS:用于防止请求URL时有些系统会进行安全验证而导致请求失败) OkHttpClient okHttpClient = new OkHttpClient.Builder().hostnameVerifier( new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslSession) { return true; } } ).build(); // 如果是JDK1.8以上的,那么可以采取lambda重写匿名函数的方式 /* OkHttpClient okHttpClient = new OkHttpClient.Builder().hostnameVerifier( (s, sslSession) ->{ return true; } ).build();*/ // 设置请求的参数信息 RequestBody requestBody = new FormBody.Builder() .add("key1", "test") .add("key2", "hello") .build(); // 封装请求头信息 Request request = new Request.Builder() .url(url) .post(requestBody) .addHeader("Cookie", "JSESSIONID=299571E0E40DA6E9962E41B87A669BBB") .addHeader("content-type", "application/json") .addHeader("cache-control", "no-cache") .build(); Call call = okHttpClient.newCall(request); try { Response response = call.execute(); // 返回相应结果 return response.body().string(); } catch (IOException e) { e.printStackTrace(); } return null; }}
SpingRestTemplate
请求步骤(GET和POST方式)
方式一
package com.hnu.scw.utils;import okhttp3.*;import org.apache.poi.ss.formula.functions.T;import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.web.client.RestTemplate;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.SSLSession;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;/** * @ Author :scw * @ Date :Created in 上午 10:34 2020/5/24 0024 * @ Description:请求URL的post方法工具类 * @ Modified By: * @Version: $version$ */public class HttpPostUtils { /** * 执行 POST 请求 通过Spring 的restTemplate方式 * @param url 请求URL * @param parameter 请求参数 * @return 响应结果字符串 */ public String doRequestPostByRestTemplate(String url, Object parameter) { RestTemplate template = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); // 设置请求的格式为:json MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8"); headers.setContentType(type); HttpEntity entity = new HttpEntity(parameter,headers); // POST方式,如果要用GET,则为getForObject即可 String result = template.postForObject(url, entity, String.class); return result; } /** * 执行 POST 请求 通过Spring 的restTemplate方式二 * @param url 请求URL * @param parameter 请求参数(PS:一般为java实体) * @param backDto 相应的结果实体 * @return 响应结果实体 */ public T doRequestPostByRestTemplate(String url, Object parameter, Class backDto) { RestTemplate template = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); // 设置请求的格式为:json MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8"); headers.setContentType(type); HttpEntity entity = new HttpEntity(parameter,headers); // POST方式,如果要用GET,则为getForObject即可 String result = template.postForObject(url, entity, String.class); // 将json字符串转为实体 return JSON.parseObject(result, backDto); }}
方式二:
package com.hnu.scw.utils;import okhttp3.*;import org.apache.poi.ss.formula.functions.T;import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.web.client.RestTemplate;import javax.net.ssl.HostnameVerifier;import javax.net.ssl.SSLSession;import java.io.*;import java.net.HttpURLConnection;import java.net.URL;import java.net.URLEncoder;import java.util.Map;/** * @ Author :scw * @ Date :Created in 上午 10:34 2020/5/24 0024 * @ Description:请求URL的post方法工具类 * @ Modified By: * @Version: $version$ */public class HttpPostUtils { /** * 执行 POST 请求 通过Spring 的restTemplate方式的方式二 * @param url 请求URL * @param parameter 请求参数 * @return 响应结果实体类型 */ public <T> T doRequestPostByRestTemplateEntity(String url, Object parameter, Class<T> backDto) { RestTemplate template = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); // 设置请求的格式为:json MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8"); headers.setContentType(type); HttpEntity entity = new HttpEntity(parameter,headers); // POST方式,如果要用GET,则为getForEntity即可 ResponseEntity<T> tResponseEntity = template.postForEntity(url, entity, backDto); return tResponseEntity.getBody(); }}
总结
本文讲述的方式各自有各自的应用场景,并不存在哪一种就是最好的形式(PS:当然不仅仅只有这些方式,比如还有apache的httpClient,CloseableHttpClient以及springCloud中常见的Fegin)。
实际工作中发出http的请求是相对的多,对于其内部的执行流程和实现原理要去掌握(PS:网络协议+socket+netty都是需要掌握)。
针对常用的场景和技术要学会去总结,分析各自的利弊,而不要只会用而不明白其内部。
通过阅读本文内容之后,建议将“输入一个URL地址,然后回车敲击显示结果”,这个链路的整个过程都去学习和掌握,你会发现更多的美哦!
小彩蛋:如果觉得公众号文章内容看起来显得比较多,那么还可以在我的博客中进行查阅哦,还有更多的惊喜等着你的光顾。
https://blog.csdn.net/Cs_hnu_scw/article/details/106311101