HttpURLConnection 简单使用

URLConnection
  • jdk 自带,调用接口传递参数比较麻烦
  • 使用 UrlConnection 比直接使用 Socket 要简单的多,不用关心状态和线程治理。
  • UrlConnection 基于Http协议,只是进行了封装,添加了一些额外规则(如头信息),本质上也是建立TCP连接,利用Socket实现连接和传输数据的,一般每次请求方法完成需要在 finally 里关闭连接。
Wireshark 抓包

由于 Wireshark 只能抓取通过网关的包,而本地搭建的服务器不经过网关,因此不能直接抓取,根据网上的 route add IP地址 mask 255.255.255.255 网关IP 添加路由之后仍不成功,最终选择安装 npcap-1.60 成功实现抓包

虽然我连的无线网,但需要选择有线的 Adapter for loopback traffic capture 抓取本地包
在这里插入图片描述

一、请求网络资源
    public void getUrl() {
        BufferedInputStream bufferedInputStream = null;
        BufferedOutputStream bufferedOutputStream = null;
        try {
            URL url = new URL("http://alifei05.cfp.cn/creative/vcg/veer/1600water/veer-121291824.jpg");
            URLConnection urlConnection = url.openConnection();
            urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36");
            InputStream inputStream = urlConnection.getInputStream();
            bufferedInputStream = new BufferedInputStream(inputStream);
            bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(new File("C:\Users\Administrator\Pictures\图标\1.jpg")));
            int len;
            byte[] bytes = new byte[1024];
            while ((len = bufferedInputStream.read(bytes)) != -1) {
                bufferedOutputStream.write(bytes, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bufferedOutputStream.flush();
                assert bufferedOutputStream != null;
                bufferedOutputStream.close();
                bufferedInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

如上代码将 jpg 文件下载到了本地

二、带参数请求

封装打开连接方法

    public HttpURLConnection openConnection(URL url) throws IOException {
        URLConnection urlConnection = url.openConnection();
        if (!(urlConnection instanceof HttpURLConnection)) {
            throw new IllegalStateException("HttpURLConnection required for [" + url + "] but got: " + urlConnection);
        }
        return (HttpURLConnection) urlConnection;
    }
1、参数类型 application/x-www-form-urlencoded

application/x-www-form-urlencoded 默认的提交方式,同GET类似,将参数组装成Key-value方式,用&分隔,但数据存放在body中提交

在这里插入图片描述
postman 看的不直观,使用 Wireshark 抓包查看
在这里插入图片描述

如上从 postman 可以看到 application/x-www-form-urlencoded 参数类型传递 body 只需要使用 & 拼接即可

public void getParamsFrom() throws IOException {
        String str = "http://127.0.0.1:8080/okhttp3/post/params_from";
        URL url = new URL(str);
        HttpURLConnection urlConnection = openConnection(url);
        urlConnection.setDoInput(true);
        urlConnection.setDoOutput(true);

        //设置请求方式
        urlConnection.setRequestMethod("POST");
        urlConnection.setUseCaches(false);
        urlConnection.setConnectTimeout(60 * 1000);g
        urlConnection.setReadTimeout(60 * 1000);

        //设置参数类型
        urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;");
        //保持连接
        urlConnection.setRequestProperty("Connection", "Keep-Alive");

        urlConnection.connect(); // 配置请求信息需要在连接直接配置 顺序不可颠倒

        OutputStream outputStream = urlConnection.getOutputStream();

        outputStream.write(("name=admin&" + "password=123456").getBytes());
        outputStream.flush();
        outputStream.close();

        StringBuilder stringBuilder = new StringBuilder();
        BufferedInputStream bufferedInputStream = new BufferedInputStream(urlConnection.getInputStream());
        byte[] bytes = new byte[1024];
        while (bufferedInputStream.read(bytes) != -1) {
            stringBuilder.append(new String(bytes));
        }
        log.info(stringBuilder.toString());
        bufferedInputStream.close();
    }
2、参数类型 Content-Type:multipart/form-data;

form 表单上传表单 Content-Type:application/x-www-form-urlencoded

如下图使用 postman 发送请求时 application/x-www-form-urlencoded 有文件和文本需要将 body 封装成如下形式
在这里插入图片描述
postman 看的不直观,使用 Wireshark 抓包查看
在这里插入图片描述

注意:boundary(分隔符),它是用来隔开提交的表单中不同部分的数据或者分割多个文件。在提交multipart/form-data请求时,设置Content_Type属性时,必须要同时指定所使用的boundary,否则上传过程中会报错,导致上传不成功。

public void getParamsFromFile() throws IOException {
        String dash = "--";
        String boundary = generateBoundary();
        String newLine = "\r\n";
        String str = "http://127.0.0.1:8080/okhttp3/post/params_from_async";
        URL url = new URL(str);
        HttpURLConnection urlConnection = openConnection(url);
        urlConnection.setDoInput(true);
        urlConnection.setDoOutput(true);

        //设置请求方式
        urlConnection.setRequestMethod("POST");
        urlConnection.setUseCaches(false);
        urlConnection.setConnectTimeout(60 * 1000);
        urlConnection.setReadTimeout(60 * 1000);

        //设置参数类型
        urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        //保持连接
        urlConnection.setRequestProperty("Connection", "Keep-Alive");

        urlConnection.connect(); // 配置请求信息需要在连接直接配置 顺序不可颠倒
        OutputStream outputStream = urlConnection.getOutputStream();
        File file = new File(System.getProperty("user.dir") + "/file" + "/1.jpg");
        String formDataKey = "name";
        String formData = "admin";
        String formTextData = dash + boundary + newLine +
                "Content-Disposition: form-data; name=\"" + formDataKey + "\"" + newLine +
                "Content-Type: text/plain; charset=utf-8" + newLine +
                newLine +// important !
                formData + newLine +
                dash + boundary + newLine;
        outputStream.write(formTextData.getBytes());
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
        // file data
        String fileKey = "file";
        String fileContentType = "image/jpeg";

        String fileHeader = "Content-Disposition: form-data; name=\"" + fileKey + "\"; filename=\"" + file.getName() + "\"" + newLine +
                "Content-Type:" + fileContentType + newLine +
                // 可以不写,有默认值
                "Content-Transfer-Encoding: binary" + newLine +
                newLine;// important !
        outputStream.write(fileHeader.getBytes());

        int len;
        byte[] bytes = new byte[1024];
        while ((len = bufferedInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
        }
        outputStream.write((newLine + dash + boundary + dash + newLine).getBytes());
        outputStream.flush();
        outputStream.close();
        bufferedInputStream.close();

        StringBuilder stringBuilder = new StringBuilder();
        BufferedInputStream bufferedInputStream1 = new BufferedInputStream(urlConnection.getInputStream());
        while (bufferedInputStream1.read(bytes) != -1) {
            stringBuilder.append(new String(bytes));
        }
        log.info(stringBuilder.toString());
    }
    // 生成 boundary
    private String generateBoundary() {
        return "--------------------------" +
                UUID.randomUUID().toString().replace("-", "");
    }
3、HTTP头中的Content-Transfer-Encoding

不同于Content-Type,这个域不是必须的。不过,仅仅定义一种Content-Transfer-Encoding也是不可以的。在有效地传输巨大的二进制数据和便于阅读的编码数据之间要有一个折中。所以,至少要有两种编码格式:易读的,和稠密的(高压缩率的)。

Content-Transfer-Encoding支持以下数据格式:BASE64, QUOTED-PRINTABLE, 8BIT, 7BIT, BINARY, X-TOKEN。这些值是大小写不敏感的。

当不设置Content-Transfer-Encoding的时候,默认就是7BIT。7BIT的含义是所有的数据以ASC-II格式的格式编码,8BIT则可能包含非ASCII字符。BINARY可能不止包含非ASCII字符,还可能不是一个短行(超过1000字符)。

上述代码有很多地方需要优化,只是做简单的测试,正式开发需要进行二次封装,文章借鉴了其他博客,目前参考的博客链接找不到了,如有侵权联系删除。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值