关于JAVA发送Https请求,HttpsURLConnection和HttpURLConnection

【转】

https协议对于开发者而言其实只是多了一步证书验证的过程。这个证书正常情况下被jdk/jre/security/cacerts所管理。里面证书包含两种情况:

1、机构所颁发的被认证的证书,这种证书的网站在浏览器访问时https头显示为绿色如百度

2、个人所设定的证书,这种证书的网站在浏览器里https头显示为红色×,且需要点击信任该网站才能继续访问。而点击信任这一步的操作就是我们在java代码访问https网站时区别于http请求需要做的事情。

所以JAVA发送Https请求有两种情况,三种解决办法:

第一种情况:Https网站的证书为机构所颁发的被认证的证书,这种情况下和http请求一模一样,无需做任何改变,用HttpsURLConnection或者HttpURLConnection都可以

  • [java]view plaincopy

    1. public static void main(String[] args) throws Exception{
    2. URL serverUrl = new URL("https://xxxx");
    3. HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
    4. conn.setRequestMethod("GET");
    5. conn.setRequestProperty("Content-type", "application/json");
    6. //必须设置false,否则会自动redirect到重定向后的地址
    7. conn.setInstanceFollowRedirects(false);
    8. conn.connect();
    9. String result = getReturn(conn);
    10. }
    11. /*请求url获取返回的内容*/
    12. public static String getReturn(HttpURLConnection connection) throws IOException{
    13. StringBuffer buffer = new StringBuffer();
    14. //将返回的输入流转换成字符串
    15. try(InputStream inputStream = connection.getInputStream();
    16. InputStreamReader inputStreamReader = new InputStreamReader(inputStream, ConstantInfo.CHARSET);
    17. BufferedReader bufferedReader = new BufferedReader(inputStreamReader);){
    18. String str = null;
    19. while ((str = bufferedReader.readLine()) != null) {
    20. buffer.append(str);
    21. }
    22. String result = buffer.toString();
    23. return result;
    24. }
    25. }

第二种情况:个人所设定的证书,这种证书默认不被信任,需要我们自己选择信任,信任的办法有两种:

A、将证书导入java的运行环境中

  • 从该网站下载或者从网站开发者出获取证书cacert.crt
  • 运行命令将证书导入java运行环境:keytool -import -keystore %JAVA_HOME%\jre\lib\security\cacerts -file cacert.crt -alias xxx
  • 完成。java代码中发送https的请求和http一样,同第一种情况。

B、忽略证书验证过程,忽略之后任何Https协议网站皆能正常访问,同第一种情况

  • [java]view plaincopy

    1. import java.security.cert.CertificateException;
    2. import java.security.cert.X509Certificate;
    3. import javax.net.ssl.X509TrustManager;
    4. public class MyX509TrustManager implements X509TrustManager {
    5. @Override
    6. public void checkClientTrusted(X509Certificate certificates[],String authType) throws CertificateException {
    7. }
    8. @Override
    9. public void checkServerTrusted(X509Certificate[] ax509certificate,String s) throws CertificateException {
    10. }
    11. @Override
    12. public X509Certificate[] getAcceptedIssuers() {
    13. // TODO Auto-generated method stub
    14. return null;
    15. }
    16. }
  • [java]view plaincopy

    1. public static void main(String[] args) throws Exception{
    2. SSLContext sslcontext = SSLContext.getInstance("SSL","SunJSSE");
    3. sslcontext.init(null, new TrustManager[]{new MyX509TrustManager()}, new java.security.SecureRandom());
    4. URL url = new URL("https://xxxx");
    5. HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
    6. public boolean verify(String s, SSLSession sslsession) {
    7. System.out.println("WARNING: Hostname is not matched for cert.");
    8. return true;
    9. }
    10. };
    11. HttpsURLConnection.setDefaultHostnameVerifier(ignoreHostnameVerifier);
    12. HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory());
    13. //之后任何Https协议网站皆能正常访问,同第一种情况
    14. }

C、java代码中加载证书,必须使用HttpsURLConnection方式

  • 从网站开发者出获取生成证书的密钥库cacert.keystore
  • [java]view plaincopy

    1. import java.io.FileInputStream;
    2. import java.security.KeyStore;
    3. import java.security.cert.CertificateException;
    4. import java.security.cert.X509Certificate;
    5. import javax.net.ssl.TrustManager;
    6. import javax.net.ssl.TrustManagerFactory;
    7. import javax.net.ssl.X509TrustManager;
    8. public class MyX509TrustManager implements X509TrustManager {
    9. /*
    10. * The default X509TrustManager returned by SunX509. We'll delegate
    11. * decisions to it, and fall back to the logic in this class if the
    12. * default X509TrustManager doesn't trust it.
    13. */
    14. X509TrustManager sunJSSEX509TrustManager;
    15. MyX509TrustManager() throws Exception {
    16. // create a "default" JSSE X509TrustManager.
    17. KeyStore ks = KeyStore.getInstance("JKS");
    18. ks.load(new FileInputStream("cancert.keystore"),
    19. "changeit".toCharArray());
    20. TrustManagerFactory tmf =
    21. TrustManagerFactory.getInstance("SunX509", "SunJSSE");
    22. tmf.init(ks);
    23. TrustManager tms [] = tmf.getTrustManagers();
    24. /*
    25. * Iterate over the returned trustmanagers, look
    26. * for an instance of X509TrustManager. If found,
    27. * use that as our "default" trust manager.
    28. */
    29. for (int i = 0; i < tms.length; i++) {
    30. if (tms[i] instanceof X509TrustManager) {
    31. sunJSSEX509TrustManager = (X509TrustManager) tms[i];
    32. return;
    33. }
    34. }
    35. /*
    36. * Find some other way to initialize, or else we have to fail the
    37. * constructor.
    38. */
    39. throw new Exception("Couldn't initialize");
    40. }
    41. /*
    42. * Delegate to the default trust manager.
    43. */
    44. public void checkClientTrusted(X509Certificate[] chain, String authType)
    45. throws CertificateException {
    46. try {
    47. sunJSSEX509TrustManager.checkClientTrusted(chain, authType);
    48. } catch (CertificateException excep) {
    49. // do any special handling here, or rethrow exception.
    50. }
    51. }
    52. /*
    53. * Delegate to the default trust manager.
    54. */
    55. public void checkServerTrusted(X509Certificate[] chain, String authType)
    56. throws CertificateException {
    57. try {
    58. sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
    59. } catch (CertificateException excep) {
    60. /*
    61. * Possibly pop up a dialog box asking whether to trust the
    62. * cert chain.
    63. */
    64. }
    65. }
    66. /*
    67. * Merely pass this through.
    68. */
    69. public X509Certificate[] getAcceptedIssuers() {
    70. return sunJSSEX509TrustManager.getAcceptedIssuers();
    71. }
    72. }
  • [java]view plaincopy

      [java]view plaincopy

      1. public static void main(String[] args) throws Exception{
      2. SSLContext sslcontext = SSLContext.getInstance("SSL","SunJSSE");
      3. sslcontext.init(null, new TrustManager[]{new MyX509TrustManager()}, new java.security.SecureRandom());
      4. URL serverUrl = new URL("https://xxxx");
      5. HttpsURLConnection conn = (HttpsURLConnection) serverUrl.openConnection();
      6. conn.setSSLSocketFactory(sslcontext.getSocketFactory());
      7. conn.setRequestMethod("GET");
      8. conn.setRequestProperty("Content-type", "application/json");
      9. //必须设置false,否则会自动redirect到重定向后的地址
      10. conn.setInstanceFollowRedirects(false);
      11. conn.connect();
      12. String result = getReturn(conn);
      13. }
      14. /*请求url获取返回的内容*/
      15. public static String getReturn(HttpsURLConnection connection) throws IOException{
      16. StringBuffer buffer = new StringBuffer();
      17. //将返回的输入流转换成字符串
      18. try(InputStream inputStream = connection.getInputStream();
      19. InputStreamReader inputStreamReader = new InputStreamReader(inputStream, ConstantInfo.CHARSET);
      20. BufferedReader bufferedReader = new BufferedReader(inputStreamReader);){
      21. String str = null;
      22. while ((str = bufferedReader.readLine()) != null) {
      23. buffer.append(str);
      24. }
      25. String result = buffer.toString();
      26. return result;
      27. }
      28. }