听说你在学习:如何通过代码请求URL地址

JavaWeb 同时被 2 个专栏收录
22 篇文章 0 订阅
12 篇文章 0 订阅

小蜗牛,今天爬了多远?不急,继续爬总会到达终点。
朋友们,今天学习了多久?别慌,保持学习才会看到更好的自己。
觉得我的文章还不错的,欢迎大家还可以关注我的微信公众号:Java菜鸟进阶之路
最近会写一个系列的文章进行推出,值得期待和持续关注哦!

情景引入

旁白:今天兴致极好,开开心心的与小白玩着“网页小游戏”
小白:真开心呀,好久没有玩这些网页游戏了呢。
我:确实,工作一来,哪有这样的闲情逸致。
小白:不过,你看,咱们玩的游戏都是通过网页链接请求,然后返回给咱们这么多对应的响应内容,它这里感觉好神奇。
我:当然,它里面涉及到的内容还是非常多,可不是一下就能完整掌握的,你这思考问题的能力大大加强了嘛!
小白:这可不嘛,学习到老才行呢。不过,我经常听到同事说,快给我一个接口地址,我要向你发出请求获取信息啦,这里面到底是怎么实现的,一直都没有机会去请教他们。
我:虚心求教,这是非常值得的,不要害怕,不懂就要问,这才是应该有的态度。既然,这样的话,那我就给你科普科普。这不,正好咱们也可以“中场休息”一会,再继续游戏呢。
小白:好呀好呀!学习,游戏两不误,岂不是人生一大快事!
我:小白,长大了!

基础知识

引言

当我们输入一个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.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>3.8.0</version>
        </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> T doRequestPostByRestTemplate(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,则为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();
    }


}

彩蛋

如何获取请求URL的响应流

背景:假设我们请求的这个URL,其返回的结果是一个文件流,那么我们就需要将这个文件流输出给前端,以实现下载文件的功能;
实现步骤:先获取请求URL的响应结果的输入流,然后再通过最开始前端的HTTPServletResponse请求响应流outputStream输出即可;

HttpUrlConnect

PS:如果采取原生的请求方式,那么就比较简单,直接获取其对应的响应结果的输入流,则可以返回。

/**
     * 请求 URL 的post请求
     * @param url  请求url地址
     * @param parameters 请求参数
     * @return 响应结果流
     * @throws Exception 异常信息
     */
    public static InputStream doRequestPostMethodInputStream(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);
                // 获取输出流
                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                out.write(params.getBytes("UTF-8"));
                out.flush();
                out.close();
                // 建立连接
                conn.connect();
                // 获取响应输入流
                return conn.getInputStream();
            } catch (Exception e) {
                // 错误次数+1
                errorNumber++;
            }
        }
        return null;
    }

 
    /**
     * 请求URL并且下载其返回的文件流内容
     * @param httpServletResponse  http响应
     * @throws Exception
     */
    public void downLoadFile(HttpServletResponse httpResponse) throws Exception {
        InputStream inputStream = doRequestPostMethodInputStream("xxx", new HashMap<>());
        // 采取缓存流的方式
        OutputStream outputStream = new BufferedOutputStream(httpResponse.getOutputStream());
        httpResponse.setContentType("application/octer-stream");
        String fileName = URLEncoder.encode("测试","UTF-8");
        httpResponse.setHeader("Content-disposition","attachment;filename=" + fileName + ";");
        byte[] buff = new byte[1024];
        int length = 0;
        while((length = inputStream.read()) != -1 ){
            outputStream.write(buff, 0, length);
        }
        outputStream.flush();
    }

Spring的RestTemplate

package com.hnu.scw.utils;

import okhttp3.*;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.http.MediaType;
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 请求  获取其返回的文件流
     * @param url  请求URL
     * @param parameter 请求参数
     * @return 响应结果文件输入流
     * @throws IOException
     */
    public static InputStream doRequestPostByRestTemplateEntity(String url, Object parameter) throws IOException {
        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<Resource> responseEntity = template.postForEntity(url, entity, Resource.class);
        if(HttpStatus.OK.equals(responseEntity.getStatusCode())){
            return responseEntity.getBody().getInputStream();
        }
        return null;
    }

 /**
     * 请求URL并且下载其返回的文件流内容
     * @param httpServletResponse  http响应
     * @throws Exception
     */
    public void downLoadFile(HttpServletResponse httpResponse) throws Exception {
        InputStream inputStream = doRequestPostByRestTemplateEntity("xxx", new HashMap<>());
        // 采取缓存流的方式
        OutputStream outputStream = new BufferedOutputStream(httpResponse.getOutputStream());
        httpResponse.setContentType("application/octer-stream");
        String fileName = URLEncoder.encode("测试","UTF-8");
        httpResponse.setHeader("Content-disposition","attachment;filename=" + fileName + ";");
        byte[] buff = new byte[1024];
        int length = 0;
        while((length = inputStream.read()) != -1 ){
            outputStream.write(buff, 0, length);
        }
        outputStream.flush();
    }
}

总结

  1. 本文讲述的方式各自有各自的应用场景,并不存在哪一种就是最好的形式(PS:当然不仅仅只有这些方式,比如还有apache的httpClient,CloseableHttpClient以及springCloud中常见的Fegin);
  2. 实际工作中发出http的请求是相对的多,对于其内部的执行流程和实现原理要去掌握(PS:网络协议+socket+netty都是需要掌握);
  3. 针对常用的场景和技术要学会去总结,分析各自的利弊,而不要只会用而不明白其内部;
  4. 通过阅读本文内容之后,建议将“输入一个URL地址,然后回车敲击显示结果”,这个链路的整个过程都去学习和掌握,你会发现更多的美哦!;
  5. 如果你想利用闲暇零散的学习技术,那么不妨关注我的公众号阅读你想要的文章哦!公众号搜索:Java菜鸟进阶之路
  • 0
    点赞
  • 3
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值