HttpURLConnection链接详解

这篇具有很好参考价值的文章主要介绍了HttpURLConnection链接详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

HttpURLConnection链接详解

一、简介

简单来说,HttpURLConnection 是 Java 提供的发起 HTTP 请求的基础类库,提供了 HTTP 请求的基本功能,不过封装的比较少,在使用时很多内容都需要自己设置,也需要自己处理请求流和响应流。

二、获取连接

获取 HttpURLConnection 对象的方法如下所示:

    // 定义 URL对象
	final URL url = new URL("http//ip:port/xxx");
    // 获取 URL 链接
    URLConnection urlConnection =  url.openConnection();
    // 因为 URL 是根据 url 中的协议(此处http)生成的 URLConnection 类的子类
    // HttpURLConnection, 故此处转换为 HttpURLConnection子类,方便使用子类
    // 中的更多的API
    HttpURLConnection connection = (HttpURLConnection)urlConnection;

三、设置参数

超时时间

在 Http 请求时防止对方长时间无法连接等问题,一般会设置超时时间,可以通过如下方式设置

 	// 设置连接超时时间, 值必须大于0,设置为0表示不超时 单位为“毫秒”
    connection.setConnectTimeout(30000);   
	// 设置读超时时间, 值必须大于0,设置为0表示不超时 单位毫秒
    connection.setReadTimeout(60000);
设置请求方法

在 Http 请求中包括 GET、POST、PUT等方法,可以通过如下方法设置 HttpURLConnection的请求方法

// 设置为 GET 请求, 
connection.setRequestMethod("GET");

注意:此处 方法必须设置为 大写,否则会报如下错误

java.net.ProtocolException: Invalid HTTP method: get

可以通过定义枚举类型设置,如下所示:

// 定义请求方法枚举类  
public enum HttpMethod {
    GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
  }

// 在使用枚举设置请求方法
connection.setRequestMethod(HttpMethod.POST.name());
请求头信息

在请求时,经常会遇到设置自定义请求头,或者更改 Conent-Type 的值,可以通过如下方设置:

// 设置请求类型为 application/json
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
// 设置可接受的数据类型
connection.setRequestProperty("Accept", "*/*");
// 设置保持长链接
connection.setRequestProperty("Connection", "Keep-Alive");
// 设置自定义头 Token
connection.setRequestProperty("Token", "123456");
其他参数
// 设置不使用缓存, 默认为 true 使用缓存
connection.setUseCaches(false);
// 设置单次请求是否支持重定向,默认为 setFollowRedirects 方法设置的值
connection.setInstanceFollowRedirects(false);

// 设置是否进行重定向,注意此处为 静态方法,表示所有的请求都不支持重定向,默认为true
HttpURLConnection.setFollowRedirects(false);

注意:

所有的参数,必须在建立连接之前设置,否则会报如下错误

java.lang.IllegalStateException: Already connected

四、建立连接

显式连接

在设置完所有参数后,可以通过调用 connect 方法,进行显式建立连接。如下所示:

    // 调用打开连接, 调用此方法,只是建立一个连接,并不会发送数据。 
    connection.connect();
隐式连接

除了上面的调用 connect 显式建立连接外,在调用如下方法时,会隐式的调用此方法,建立连接。

    // 获取输出流
    connection.getOutputStream();
    // 获取输入流
    connection.getInputStream();

由于,在网络请求时,一般都会获取请求结果,故在实际应用中,一般不调用 connect() 方法进行显式打开连接。

五、发送数据

POST请求

众所周知,HTTP 中的 POST 请求的数据是包含在请求体中的。在 HttpURLConnection 中 POST 请求发送数据时,需要获取 连接的输出流对象,然后往输出流中写数据即可,如下所示:

    // 要发送的数据
    String connect = "我是一个POST请求数据";

    // 因为这个是post请求,参数要放在
    // http正文内,因此需要设为true, 默认情况下是false;
    connection.setDoOutput(true);

    // 从连接中获取 输出流对象
    OutputStream os = connection.getOutputStream();
    // 往输出流中写数据
    os.write(connect.getBytes(StandardCharsets.UTF_8));
    // 冲刷 并 关闭输出流
    os.flush();
    os.close();

注意:

1、 需要写数据时,必须调用 connection.setDoOutput(true); 方法,并且参数为 true, 且需要在调用 getOutputStream() 方法之前调用。

2、此时写的数据,只是写到了缓冲区中,并不会真正的把数据发送给资源方。

GET请求

Http 中的 GET 请求的参数是拼接在 URL 后进行发送的,所以 发送 GET 请求时,在创建 连接时把参数拼接在后面即可。

但是,有一点需要注意,如果在 GET 请求中 也调用了 getOutputStream() 方法,那么,自动就会把请求改为 POST 请求。如下源码所示:

// HttpURLConnection 中的 方法,
private synchronized OutputStream getOutputStream0() throws IOException {
        try {
            if (!this.doOutput) {
               
            } else {
                // 如果设置的 方法为 GET 则改为 POST
                if (this.method.equals("GET")) {
                    this.method = "POST";
                }
            }
        }catch(Exception e){
            
        }
}

六、响应数据

请求结果

在 HTTP 请求中一般是需要知道请求状态,在 HttpURLConnection 中可以通过如下方式获取请求状态

// 获取请求状态,此状态即为 HTTP 请求的状态 200:成功,404:找不到资源 等
int responseCode = connection.getResponseCode();

// 获取请求描述信息
String msg = connection.getResponseMessage();

获取头信息

获取响应头有如下几种方式:

// 1、获取所有的响应头信息
 Map<String, List<String>> headerFields = connection.getHeaderFields();

// 2、根据头信息名称获取响应头信息
String connectionHeader =  connection.getHeaderField("Connection");

// 3、根据头信息索引获取响应头信息, 此下标 必须大于 0。
String secHeader = connection.getHeaderField(2);

读取数据

读取响应数据也是比较简单的,可以首先通过 HttpURLConnection 中的 getInputStream() 方法 获取输入流,然后,通过输入流获取数据即可,如下所示:

	// 获取输入流
	InputStream inputStream = connection.getInputStream();
	// 定义一个临时字节输出流
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        // 开始读取数据
        byte[] buffer = new byte[256];
        int len = 0;
        while ((len = inputStream.read(buffer)) > 0){
            baos.write(buffer,0, len);
        }
        return new String(baos.toByteArray(), StandardCharsets.UTF_8);
    } finally {
        // 关闭输入、输出流
        inputStream.close();
        baos.close();
    }

七、上传下载

上传

在普通 Web 页面中上传文件是很简单的,只需要把 from 标签中加上 enctype="multipart/form-data" 即可,剩下的都交给浏览器去完成发送数据的收集并发送 Http 请求即可。

但是,在 HttpURLConnection 中脱离了浏览器,就需要我们自己去完成数据收集并发送请求了。那么我们首先看下浏览器是怎么收集上传数据,并发送请求的。

先看下浏览器发送上传时间的请求正文格式:

// 请求头中的 Content-Type 属性 其中定义了属性分割线  
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryfdRf0g4cPSTVeLkJ

// 请求数据正文信息
------WebKitFormBoundaryfdRf0g4cPSTVeLkJ
Content-Disposition: form-data; name="images"; filename="20150703212056_Yxi4L.jpeg"
Content-Type: image/jpeg


------WebKitFormBoundaryfdRf0g4cPSTVeLkJ
Content-Disposition: form-data; name="checkRecord"

{"describe":"","rectify":"立即整改"}
------WebKitFormBoundaryfdRf0g4cPSTVeLkJ--

分析上面的的数据我们能够发下如下规则:

  1. 数据正文中的第一行 ------WebKitFormBoundaryfdRf0g4cPSTVeLkJ 作为分隔符,然后是 \r\n 回车换行符。
  2. 第二行 Content-Disposition: form-data; name="images"; filename="*****", 代表 form 表单数据域,其中 name 表示 接口属性值,filename 为文件名称。
  3. 第三行 Content-Type: image/jpeg 表示上传文件的类型。
  4. 第四行是一个 回车换行符。
  5. 第五行 是 数据内容,由于此处为 图片故没有显示出来。
  6. 后面的也是遵从上述规律。
  7. 最后一行表示结束行,注意后面多两个--

根据以上规律,我们 在 使用 HttpURLConnection 进行上传时,就可以按照此规律拼接发送的数据流。实例如下所示:

public void upload(File file) throws Exception {
    final URL url = new URL("http://localhost:10010/user/upload");

    // 获取 URL 链接
    URLConnection urlConnection =  url.openConnection();
    // 因为 URL 是根据 url 中的协议(此处http)生成的 URLConnection 类的子类
    // HttpURLConnection, 故此处转换为 HttpURLConnection子类,方便使用子类
    // 中的更多的API
    HttpURLConnection connection = (HttpURLConnection)urlConnection;

    // 自定义分割线,并设置请求头信息
    String boundary = "------------" + System.currentTimeMillis();

    connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
    // 设置请求为 POST 请求
    connection.setRequestMethod(METHOD.POST.name());
    // 打开输出流
    connection.setDoOutput(true);
    // 获取上传文件的类型
    MagicMatch magicMatch = Magic.getMagicMatch(file, false, true);
    String mimeType = magicMatch.getMimeType();

    // 获取输出流
    OutputStream outputStream = connection.getOutputStream();

    //拼接请求数据
    StringBuilder builder = new StringBuilder();
    // 第一行分割行
    builder.append("\r\n").append("--" + BOUNDARY).append( "\r\n");
    // 第二行form表单数据
    builder.append("Content-Disposition: form-data; name=\"file\"; filename=\"").append(file.getName() ).append("\"\r\n");
    // 第三行 上传数据类型
    builder.append( "Content-Type:").append(mimeType).append("\r\n");
    // 第四行一个空行
    builder.append("\r\n");
    outputStream.write(builder.toString().getBytes(StandardCharsets.UTF_8));
    // 开始写文件数据
    InputStream fileInput = new FileInputStream(file);
    byte[] buffer = new byte[512];
    int len = 0;
    while ((len = fileInput.read(buffer)) > 0){
        outputStream.write(buffer, 0, len);
    }


    // 开始写基本数据
    StringBuilder textBuffer = new StringBuilder();
    // 分隔符行
    textBuffer.append("\r\n").append("--" + BOUNDARY).append("\r\n");
    // form表单数据
    textBuffer.append("Content-Disposition: form-data; name=\"name\"\r\n");
    // 一个空行
    textBuffer.append("\r\n");
    // 数据值
    textBuffer.append("张三");
    outputStream.write(textBuffer.toString().getBytes(StandardCharsets.UTF_8));

    // 写入结束行
    outputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8));
    outputStream.flush();
    outputStream.close();
    fileInput.close();
    int responseCode = connection.getResponseCode();
    printHeaders(connection.getHeaderFields());
    if(responseCode != 200){
        LOGGER.error("请求失败, code: {}, message: {}", responseCode, connection.getResponseMessage());
    }else {
        InputStream inputStream = connection.getInputStream();
        String reader = reader(inputStream);
        LOGGER.info("服务端返回数据为: \n {}", reader);
    }
}

注意:

基本数据比 file 缺少 Content-Type: image/jpeg 行

下载

文件的下载就比较简单了,获取输入流,然后读取输入流,并把读到的数据保存到本地即可,一下是下载网络上的图片为例。

/**
     * 下载
     * @param url 下载文件路径
     * @param distDir 保存的文件路径
     */
   public void download(String url, String distDir) throws Exception {
       // 获取连接
       HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();

       // 设置请求方法
       connection.setRequestMethod("GET");
       connection.setRequestProperty("Charset", "UTF-8");

       // 获取文件名
       String fileUrl = connection.getURL().getFile();
       String fileName = fileUrl.substring(fileUrl.lastIndexOf(File.separatorChar) + 1);

       LOGGER.info("文件名:{} -- {}", fileName,  File.separator);
       String filePath = distDir + File.separatorChar + fileName;
       File file = new File(filePath);
       if(!file.getParentFile().exists()){
           file.getParentFile().mkdirs();
       }
       // 获取输入流,并写入文件
       try (InputStream inputStream = connection.getInputStream();
            OutputStream os = new FileOutputStream(file)) {
           byte[] buffer = new byte[256];
           int len = 0;
           while ((len = inputStream.read(buffer)) > 0) {
               os.write(buffer, 0, len);
           }
           os.flush();
       }

   }

九、总结

  1. 通过 URL 类的 openConnection() 方法获取请求连接
  2. 如果需要写入数据需要调用 setDoOutput(true) 打开输出流
  3. 在调用connection()getOutputStream()getInputStream() 方法之前设置好请求参数。
  4. 如果调用 getOutputStream() 方法,则会把把请求方法改为 POST
  5. 建立连接和调用 getOutputStream() 方法写入数据并关闭连接后,也不会发送数据,只有调用 getInputStream()才会真正的发送数据。
  6. 在使用 HttpURLConnection 上传数据时,需要仿照浏览器上传,手动拼接数据格式

关注【猿博园】回复“http” 可获取源码
HttpURLConnection链接详解文章来源地址https://www.toymoban.com/news/detail-416582.html

到了这里,关于HttpURLConnection链接详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • HttpURLConnection设置代理的两种方式

    前言:最近写一个东西需要用到HttpURLConnection,但是写的过程中遇到了问题,想通过fiddler抓包,查看具体情况,但是却发现fiddler竟然抓不到java程序的包。查询之后发现使用代理即可解决这个问题,两种方式使用代理。 第一种:直接设置代理 第二种:1.5之后,可以通过Proxy类

    2024年02月15日
    浏览(50)
  • 安卓App使用HttpURLConnection发送请求与上传文件

    系统内置http请求工具为 HttpURLConnection httpClient 是 apache 的开源工具 okHttp 使用更简单,语法相对HttpURLConnection也简洁了许多,需要在graddle添加依赖。 本文主要讲解如何使用HttpURConnection向服务器发送Reqest, 保存Response内容,如何上传文件等内容。 step-1: 创建1个URL 对象 step-2: 创建

    2024年02月03日
    浏览(38)
  • 使用HttpURLConnection发送POST请求并携带请求参数

    这里的param是请求参数,需要将其转换为字节数组后写入输出流。 这里的response是响应数据,需要将其读取为字符串后使用。 完整的示例代码如下所示: 需要注意的是,以上示例代码中的请求参数是以字符串形式传递的,如果需要传递复杂的请求参数,可以考虑使用JSON等格

    2024年02月04日
    浏览(57)
  • java 发送 http 请求练习两年半(HttpURLConnection)

    1、起一个 springboot 程序做 http 测试: 2、写一个 HttpURLConnection 自定义客户端 3、测试 get 和 post 请求 4、控制台输出结果 中间遇到一些坑,经常以为 http 会有方法像 openfeign 那样传入请求参数,忽略了路径拼接, 启动的 springboot 接收的 post 的请求体为 List 类型,且 Content-Type

    2023年04月22日
    浏览(45)
  • Java实现HTTP请求的几种方式-HttpURLConnection(一)

    在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接口(短信、天气等)。 准备两个项目: 项目A: 服务提供者 项目B:服务消费者 在项目A中

    2024年02月16日
    浏览(45)
  • HttpURLConnection中请求头中携带Token的使用方法

    一般会在头部添加认证信息,如token值或BasicAuth认证的 Authorization值

    2024年02月05日
    浏览(43)
  • 动态链接库dll详解

        DLL就是整个Windows操作系统的基础。动态链接库不能直接运行,也不能接收消息他们是一些独立的文件。     Windows API中的所有函数都包含在DLL中。     其中有三个最重要的DLL     kernel32.dll ,它包含用于管理内存、线程和进程的各个函数;     User32.dll ,它包含用于执行

    2024年02月06日
    浏览(41)
  • 【Linux】—— 详解软硬链接

    前言: 本期,我将要给大家讲解的是有关 Linux下 软硬链接 的相关知识!!! 目录 前言 (一)理解硬链接 1.什么是硬链接 2.创建硬链接  3.硬链接的使用场景 (二)理解软链接 1.什么是软链接 2.创建软链接 3.软链接使用场景 (三)硬链接和软链接的对比 总结 文件共享可以

    2024年02月03日
    浏览(38)
  • 【c语言】编译链接--详解

    在ANSI C的任何⼀种实现中,存在两个不同的环境。 第1种是 翻译环境 ,在这个环境中源代码被转换为可执⾏的机器指令。 第2种是 执行环境 ,它⽤于实际执⾏代码 翻译环境 一个程序可能不止一个.c文件 • 多个.c⽂件单独经过编译出编译处理⽣产对应的目标文件 • 多个⽬标

    2024年02月08日
    浏览(39)
  • 详解超链接<a>href属性

    href属性规定链接的目标地址(URL) (1)绝对URL-其可以跳转到另外一个网址 (2)相对URL-其指向站点内的某个文件 eg(href = \\\"index.html\\\") (3)锚URL-指向页面中的锚 eg: 其可以指向本页面你设置锚的任意位置 特例 href = \\\"#top\\\"或者href = \\\"#\\\"链接都直接可以返回页面顶部 当href取空值

    2024年02月12日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包