详解Java如何向http/https接口发出请求

2025-01-24 16:50

本文主要是介绍详解Java如何向http/https接口发出请求,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下...

Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一个工具类

import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.CertificateEjavascriptxception;
import java.security.cert.X509Certificate;

public class Testt {

    /*
    HostnameVerifier 是一个Java接口
    其中的verify方法用来在下面的类中提供主机名的SSL校验
    这里个人用不做具体校验所有的主机名都给过
     */
    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier()
    {
        public boolean verify(String arg0, SSLSession arg1) {
            return true;
        }
    };

    /*
    trustAllHosts方法 方法创建了一个 TrustManager 接口的匿名实现
    它是用来检查证书的,无论是服务器证书还是客户端证书
    这通过重写 checkServerTrusted 和 checkClientTrusted 方法为空 不做任何检查
     */
    public static void trustAllHosts() {
        TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager()
        {

            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[] {};
            }

            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

            }

            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {

            }
        }

        };

        /*
        SSLContext 使用上述的 TrustManager 初始化一个 SSLContext 实例
        并将其设置为 HttpsURLConnection 的默认 SSLSocketFactory
        这允许 HttpsURLConnection 信任所有SSL证书
        TLS是握手协议的一种
         */
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        }
        catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 发出请求的具体方法
     * @param urlPath  https协议接口的路径 https://xxxxxx
     * @param json  发出请求需要携带的参数,需要是Json格式
     * @return
     */
    public static String doPostToJson(String urlPath, String Json) {
        String result = "";
        BufferedReader reader = null;
        HttpURLConnection conn = null;

        try {
            /*
            掉用上面的静态方法,使得请求发出时,作为调用者的我们对服务端所拥有的任何https证书都是兼容的
            这里说一句题外话:一般情况下,作为接口使用者trustAllHosts方法里面的代码是不变的,因为你作为使用者
                          总没道理说让人家服务端兼容你什么,除非你是证书的使用者,不过这种情况会有证书厂商
                          告诉你如何做,不得不说厂商服务是个好东西
             */
            trustAllHosts();

            URL url = new URL(urlPath);

            /*
            如果协议是 https,则使用 HttpsURLConnection 并设置 HostnameVerifier 为 DO_NOT_VERIFY。
            否则,使用 HttpURLConnection
             */
            if (url.getProtocol().toLowerCase().equals("https")) {
                HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
                httpsConn.setHostnameVerifier(DO_NOT_VERIFY);
                conn = httpsConn;
            }
            else {
                conn = (HttpURLConnection) url.openConnection();
            }

            // 设置请求以POST形式发出
            conn.setRequestMethod("POST");
            // 是否携带请求提,POST和GET请求必须为true
            conn.setDoOutput(true);
            // 是否会获取服务端China编程的响应,默认是true
            conn.setDoInput(true);
            //禁用缓存
            conn.setUseCaches(false);
            // Keep-Alive告诉服务端对已有的TCP连接保持一定时间的活性,以保障后续发出的请求不需要建立新的TCP连接,从而减少网络开销
            conn.setRequestProperty("Connection", "Keep-Alive");
            //字符集,这个配置不是标准的请求头,但是有些妖孽系统会读取这个
            conn.setRequestProperty("Charset", "UTF-8");
            // 这个是请求格式,告诉服务端这个请求发送的是Json数据以及字符集
            conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
            // 告诉服务端,相应格式也希望是json格式
            conn.setRequestProperty("accept", "application/json");

            //如果参数不为空则将参数以字节数流的方式写入请求体里面
            if (Json != null) {
                byte[] writebytes = Json.getBytes();
                conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length));
                OutputStream outwritestream = conn.getOutputStream();
                outwritestream.write(Json.getBytes());
                outwritestream.flush();
                outwritestream.close();
            }

  android          //读取响应,相应javascript数据也是一个json
            if (conn.getResponseCode() == 200) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
                result = reader.readLine();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            //读取相应用的输入流需要在这里关闭,而写入请求参数的输出流是随用随关的
            if (reader != null) {
                try {
                    reader.close();
                    conn.disconnect();
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

}

对于上面的代码,重点要说明的第一点是HostnameVerifier接口提供的方法,它主要用于访问https协议下的接口时,验证当前已和你建立连接的hostname(主机名)和连接的SSLSession(SSL会话)证书是否匹配,防止中间人攻击,比如可以如下操作

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.IOException;
importpython java.net.URL;

public class HostnameVerifierExample {

    public static void main(String[] args) {
        try {
            // 创建一个URL对象
            URL url = new URL("https://xxxxx");

            // 打开HTTPS连接
            HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

            // 设置自定义的HostnameVerifier
            HostnameVerifier customVerifier = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    // 在这里实现你的验证逻辑
                    // 例如,你可以比较hostname和session中的证书信息
                    // 为了简单起见,这里我们直接接受任何主机名(不推荐这样做,有安全风险)
                    // 在实际应用中,你应该根据你的安全策略来实现这个逻辑
                    // 比如,你可以检查hostname是否与你预期的服务器主机名匹配
                    // 或者,你可以使用HttpsURLConnection.getDefaultHostnameVerifier()来获取默认的验证器,并基于它的结果进行扩展

                    // 这是一个不安全的示例,仅用于说明如何使用verify方法
                    // 在实际应用中,你应该避免这样做
                    return true; 

                    // 更安全的做法可能是这样的:
                    // if ("expected.hostname".equals(hostname)) {
                    //     return true;
                    // } else {
                    //     HostnameVerifier defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
                    //     return defaultVerifier.verify(hostname, session);
                    // }
                }
            };

            // 设置自定义的HostnameVerifier到连接中
            connection.setHostnameVerifier(customVerifier);

            // 继续处理HTTPS连接,比如读取响应等
            // ...

            // 关闭连接
            connection.disconnect();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

第二是trustAllHosts方法里面的东西,TrustManager是用来实现证书验证的类,X509TrustManager是X.509 证书的验证实现,通俗的讲是一个基础的证书,因此我上面的代码中也说了,如果你是正式的https证书使用者,会有厂商服务告诉你怎么验证证书,在X509TrustManager 中提供了三个方法

getAcceptedIssuers():返回此信任管理器接受的发行者证书(根证书或中间证书)数组。在上面的代码中,这个方法返回了一个空数组,意味着它不做任何特定的发行者证书获取

checkServerTrusted(X509Certificate[] certs, String authType):验证服务器提供的证书链是否可信。在代码中,这个方法被空实现了,意味着不会进行任何验证。

checkClientTrusted(X509Certificate[] certs, String authType):验证客户端提供的证书链是否可信(在需要客户端证书的情况下)。同样,在代码中,这个方法也被空实现了

到此这篇关于详解Java如何向http/https接口发出请求的文章就介绍到这了,更多相关Java https接口发出请求内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!

这篇关于详解Java如何向http/https接口发出请求的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153216

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置