当前位置: 代码网 > it编程>编程语言>Java > 详解Java如何向http/https接口发出请求

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

2025年01月24日 Java 我要评论
用java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一个工具类import javax.net.ssl.*;import java.io.buffer

用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.certificateexception;
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);
            // 是否会获取服务端的响应,默认是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();
            }

            //读取响应,相应数据也是一个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;
import 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接口发出请求内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com