需要的依赖:
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
参考视频:
https://www.bilibili.com/video/BV1W54y1s7BZ
1、原生JDK实现的网络请求
这个在狂神的爬虫上面有看到过原生的方式
当时还不明白这个技术其实就是后台的Ajax
@Test public void quickStart() throws IOException { InputStream inputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; try { // 原生JDK API 发送请求 String urlString = "https://www.baidu.com/"; URL url = new URL(urlString); URLConnection urlConnection = url.openConnection(); HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; httpURLConnection.setRequestMethod("GET"); httpURLConnection.setRequestProperty("aaa", "123"); inputStream = httpURLConnection.getInputStream(); inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); bufferedReader = new BufferedReader(inputStreamReader); String line = null; while (null != ( line = bufferedReader.readLine())) { System.out.println(line); } } catch (Exception e) { e.printStackTrace(); } finally { bufferedReader.close(); inputStreamReader.close(); inputStream.close(); } }
2、使用ApacheHttpClient发送请求:
@Test public void useHttpClient() throws IOException { // 使用 HttpClient Get 无参请求实现 CloseableHttpClient closeableHttpClient = null; CloseableHttpResponse closeableHttpResponse = null; HttpEntity httpEntity = null; try { // 创建一个可关闭的Http客户端对象 closeableHttpClient = HttpClients.createDefault(); // 要请求的地址 String urlString = "https://www.baidu.com/"; // GET参数需要进行URL编码处理 String param1 = "orderId=21343000123324"; String param2 = "orderRemark=大三大四1王企鹅1 哇多久啊是巴西 &%……¥%"; param1 = URLEncoder.encode(param1, StandardCharsets.UTF_8.name()); param2 = URLEncoder.encode(param2, StandardCharsets.UTF_8.name()); // 根据地址创建一个Http请求对象 这里使用的是GET请求对象 // HttpGet httpGet = new HttpGet(urlString); HttpGet httpGet = new HttpGet(urlString + "?" + param1 + "&" + param2); // 浏览器伪装信息 httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38"); // 防盗链设置 https://www.jianshu.com/p/0a1338db6cab httpGet.addHeader("Referer", "https://ntp.msn.cn/"); // 客户端对象带着请求对象 执行请求发送, 返回响应对象 closeableHttpResponse = closeableHttpClient.execute(httpGet); // 可以从响应对象获取对应的响应信息 StatusLine statusLine = closeableHttpResponse.getStatusLine(); System.out.println(statusLine); // HTTP/1.1 200 OK // 响应不成功状态直接结束后续逻辑 if (HttpStatus.SC_OK != statusLine.getStatusCode()) return; ProtocolVersion protocolVersion = statusLine.getProtocolVersion(); // HTTP/1.1 int major = protocolVersion.getMajor(); // 1 主版本协议号 int minor = protocolVersion.getMinor(); // 1 附属小版本协议号 String protocol = protocolVersion.getProtocol(); // HTTP int statusCode = statusLine.getStatusCode(); // 200 String reasonPhrase = statusLine.getReasonPhrase(); // OK Header[] allHeaders = closeableHttpResponse.getAllHeaders(); for (Header header : allHeaders) { System.out.println("Response Header -> " + header.getName() + " : " + header.getValue()); } // 从响应对象中获取响应实体对象 httpEntity = closeableHttpResponse.getEntity(); Header contentType = httpEntity.getContentType(); String contentTypeName = contentType.getName(); // Content-Type String contentTypeValue = contentType.getValue(); // Content-Type: text/html;charset=utf-8 // 这个响应头不常见 // Header contentEncoding = httpEntity.getContentEncoding(); // null // String contentEncodingName = contentEncoding.getName(); // String contentEncodingValue = contentEncoding.getValue(); // 使用实体工具类转换成字符结果 String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8); // System.out.println(httpEntityResult); } catch (Exception exception) { exception.printStackTrace(); } finally { // 最后调用此方法确保资源释放 EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); } }
3、下载图片资源:
@Test public void downloadWebPicture() throws Exception { // 请求发送 CloseableHttpClient closeableHttpClient = HttpClients.createDefault(); String resource = "https://img.zcool.cn/community/01088b5a052431a801204a0e253198.jpg@1280w_1l_2o_100sh.jpg"; HttpGet httpGet = new HttpGet(resource); CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet); HttpEntity httpEntity = closeableHttpResponse.getEntity(); // 类型解析 Header contentType = httpEntity.getContentType(); String contentTypeValue = contentType.getValue(); // image/jpeg String fileTypeSuffix = contentTypeValue.split("/")[1]; // jpeg // 文件下载 byte[] bytes = EntityUtils.toByteArray(httpEntity); String localPath = "C:\\Users\\Administrator\\Desktop\\test." + fileTypeSuffix; OutputStream outputStream = new FileOutputStream(localPath); outputStream.write(bytes); // 资源释放 outputStream.close(); EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); }
4、配置代理主机:
@Test public void proxySettings() throws Exception { CloseableHttpClient closeableHttpClient = HttpClients.createDefault(); String target = "https://www.baidu.com/"; HttpGet httpGet = new HttpGet(target); // 代理主机的信息 http://www.66ip.cn/ String ip = "176.121.1.81"; int port = 8181; HttpHost httpHost = new HttpHost(ip, port); // 创建请求配置对象 RequestConfig requestConfig = RequestConfig .custom() .setProxy(httpHost) // 设置代理主机的信息 .build(); // 设置请求配置 httpGet.setConfig(requestConfig); CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet); HttpEntity httpEntity = closeableHttpResponse.getEntity(); Header[] allHeaders = closeableHttpResponse.getAllHeaders(); for (Header header : allHeaders) { System.out.println("Response Header -> " + header.getName() + " : " + header.getValue()); } String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8); System.out.println(httpEntityResult); // 资源释放 EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); }
5、设置超时相关的配置:
@Test public void proxySettings() throws Exception { // 请求发送 CloseableHttpClient closeableHttpClient = HttpClients.createDefault(); String target = "https://www.baidu.com/"; HttpGet httpGet = new HttpGet(target); // 代理主机的信息 http://www.66ip.cn/ String ip = "176.121.1.81"; int port = 8181; HttpHost httpHost = new HttpHost(ip, port); // 创建请求配置对象 RequestConfig requestConfig = RequestConfig .custom() .setProxy(httpHost) .setConnectTimeout(5000) // 设置连接超时的上限 TCP3次握手的时限 .setSocketTimeout(3000) // 设置读取超时上限 从请求的网址中获取响应数据的间隔时限(因为并不是一次请求就完成了加载) .setConnectionRequestTimeout(3000) // 从HttpClient连接池中获取connection对象的时限 .build(); // 设置请求配置 httpGet.setConfig(requestConfig); CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpGet); HttpEntity httpEntity = closeableHttpResponse.getEntity(); Header[] allHeaders = closeableHttpResponse.getAllHeaders(); for (Header header : allHeaders) { System.out.println("Response Header -> " + header.getName() + " : " + header.getValue()); } String httpEntityResult = EntityUtils.toString(httpEntity, StandardCharsets.UTF_8); System.out.println(httpEntityResult); // 资源释放 EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); }
6、MIME-TYPE 邮件扩展类型 与POST请求
mime-type 就是具体文件类型的前面的所属规范类型
在Tomcat里面配置的web.xml信息就可以看到所有的规范类型了
E:\apache-tomcat-8.5.70\conf\web.xml
片段:
<mime-mapping> <extension>zirz</extension> <mime-type>application/vnd.zul</mime-type> </mime-mapping> <mime-mapping> <extension>zmm</extension> <mime-type>application/vnd.handheld-entertainment+xml</mime-type> </mime-mapping>
常见Content-type:
# 一般html表单提交 发送的类型 application/x-www-form-urlencoded # html上传文件规范的类型 multipart/form-data # 目前主流规范的类型 application/json
POST表单类型提交案例:
1、客户端请求代码
@Test public void postWithFormType() throws Exception { CloseableHttpClient closeableHttpClient = HttpClients.createDefault(); String target = "http://localhost:8080/mvc-framework/test/testMethod2"; // 首先创建POST请求对象 HttpPost httpPost = new HttpPost(target); // 设置表单需要提交的参数 List<NameValuePair> nvpList = new ArrayList<>(); nvpList.add(new BasicNameValuePair("username", "张三")); nvpList.add(new BasicNameValuePair("password", "w123e21")); // 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(nvpList, Consts.UTF_8); // 设置表单类型实体对象 httpPost.setEntity(urlEncodedFormEntity); // 客户端执行请求发送 CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost); HttpEntity httpEntity = closeableHttpResponse.getEntity(); System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8)); EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); }
2、服务器处理代码:
/** * * POST请求测试 * http://localhost:8080/mvc-framework/test/testMethod2 * @param request * @param response */ // @RequestMethod(MethodType.POST) @RequestMapping(value = "/testMethod2", methodType = MethodType.POST) public void testMethod2(HttpServletRequest request, HttpServletResponse response) { System.out.println("testMethod2"); ServletUtil.printAllParamByRequestMap(request); Map<String, Object> requestAttribute = (Map<String, Object>) request.getAttribute(ServletConstants.POST_PARAM_KEY); for (String s : requestAttribute.keySet()) { System.out.println("postParam " + s + ": " + requestAttribute.get(s)); } }
服务这里没有对请求做出响应,就是打印看看没有收到参数信息:
doPost detected doGet detected testMethod2 username: [张三] password: [w123e21] postParam password: w123e21 postParam username: 张三
做了两次打印的原因是第一个打印是直接调用ServletAPI实现:
基本的POST表单请求Servlet有做识别处理
public static void printAllParamByRequestMap(HttpServletRequest request) { Map<String, String[]> parameterMap = request.getParameterMap(); for (String s : parameterMap.keySet()) { System.out.println(s + ": " + Arrays.toString(parameterMap.get(s))); } }
第二次打印是从输入流中获取识别的
/** * 从POST请求中获取参数 * @param request * @return * @throws Exception */ public static Map<String, Object> getPostParam(HttpServletRequest request) throws Exception { // 返回参数 Map<String, Object> params = new HashMap<>(); // 获取内容格式 String contentType = request.getContentType(); if (null == contentType || "".equals(contentType)) throw new ServletException("没有设置请求头项Content-Type!!!"); else contentType = contentType.split(";")[0]; // form表单格式 表单形式可以从 ParameterMap中获取 if (ServletConstants.CONTENT_TYPE_VALUE_URL_ENCODED2.equalsIgnoreCase(contentType)) { // 获取参数 Map<String, String[]> parameterMap = request.getParameterMap(); if (parameterMap != null) { for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) { params.put(entry.getKey(), entry.getValue()[0]); } } } // json格式 json格式需要从request的输入流中解析获取 if (ServletConstants.CONTENT_TYPE_VALUE_JSON2.equalsIgnoreCase(contentType)) { // 使用 commons-io中 IOUtils 类快速获取输入流内容 String paramJson = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); Map parseObject = JSON.parseObject(paramJson, Map.class); params.putAll(parseObject); } return params ; }
也可以不使用 UrlEncodedFormEntity ,使用请求头设置即可
这个意思在视频里说错了,应该是这个Entity已经在Header这么处理了
// 配置Http请求头 httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
因为表单的参数还是需要放到Entity里面发送过去的
这里特意看了下Entity的实现结构:
搜寻Entity相关的时候发现这个博客写的也很好,涉及到Cookie相关的操作
https://www.cnblogs.com/licl11092/p/9075677.html
POST + JSON类型案例:
SpringMVC接受Post JSON数据时要带上 @RequestBody给方法
普通Get参数则是@RequestParam
类注解为@RestController就可以不注解@RequestBody方法
在这里我使用的是封装的一套MVC,Servlet对JSON参数是不支持的,只能从输入流自行获取
这里JSON参数采用的是StringEntity实现存储,看了源码发现默认是text/plain类型,也允许构造器自行设置类型
@Test public void postWithFormJson() throws Exception { CloseableHttpClient closeableHttpClient = HttpClients.createDefault(); java.lang.String target = "http://localhost:8080/mvc-framework/test/testMethod2"; // 首先创建POST请求对象 HttpPost httpPost = new HttpPost(target); // 设置需要提交的JSON参数 这里做简单案例,就不去下载Fastjson来转换了,自己手写一个 String jsonParam = "{ \"username\": \"张三\", \"password\": \"w123e21\" }"; // 表单类型实体对象 装填参数信息 application/x-www-form-urlencoded StringEntity jsonEntity = new StringEntity(jsonParam , Consts.UTF_8); // 配置Http请求头 // httpPost.addHeader("Content-Type", "application/json; charset=UTF-8"); jsonEntity.setContentType(new BasicHeader("Content-Type", "application/json; charset=UTF-8")); // StringEntity 设置编码 jsonEntity.setContentEncoding(Consts.UTF_8.name()); // 设置JSON实体对象 httpPost.setEntity(jsonEntity); // 客户端执行请求发送 CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpPost); HttpEntity httpEntity = closeableHttpResponse.getEntity(); System.out.println(EntityUtils.toString(httpEntity, StandardCharsets.UTF_8)); EntityUtils.consume(httpEntity); closeableHttpResponse.close(); closeableHttpClient.close(); }
POST + 文件类型案例: