使用java.net.URLConnection来触发和处理HTTP请求

在这里经常会问到java.net.URLConnection用法, Oracle教程 简单了。

该教程基本上只显示如何触发GET请求并阅读响应。 它没有解释如何使用它来执行POST请求,设置请求头,读取响应头,处理cookie,提交HTML表单,上传文件等。

那么,如何使用java.net.URLConnection来触发和处理“高级”HTTP请求呢?

首先是免责声明:发布的代码片段都是基本的例子。 你将需要处理普通的IOExceptionRuntimeException IOException ,如NullPointerExceptionArrayIndexOutOfBoundsException并配合你自己。


准备

我们首先需要知道至lessURL和字符集。 这些参数是可选的,取决于function要求。

 String url = "http://example.com"; String charset = "UTF-8"; // Or in Java 7 and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name() String param1 = "value1"; String param2 = "value2"; // ... String query = String.format("param1=%s&param2=%s", URLEncoder.encode(param1, charset), URLEncoder.encode(param2, charset)); 

查询参数必须是name=value格式,并由&连接起来。 您通常也会使用URLEncoder#encode()以指定的字符集对查询参数进行URL编码 。

String#format()只是为了方便。 我更喜欢当我需要string连接运算符+超过两次。


使用(可选)查询参数激发HTTP GET请求

这是一个微不足道的任务。 这是默认的请求方法。

 URLConnection connection = new URL(url + "?" + query).openConnection(); connection.setRequestProperty("Accept-Charset", charset); InputStream response = connection.getInputStream(); // ... 

任何查询string应连接到URL使用?Accept-Charset头可以提示服务器参数的编码方式。如果你不发送任何查询string,那么你可以离开Accept-Charset头。 如果你不需要设置任何头文件,那么你甚至可以使用URL#openStream()快捷方法。

 InputStream response = new URL(url).openStream(); // ... 

无论哪种方式,如果另一端是一个HttpServlet ,那么它的doGet()方法将被调用,参数将由HttpServletRequest#getParameter()

出于testing目的,您可以将响应主体打印到stdout中,如下所示:

 try (Scanner scanner = new Scanner(response)) { String responseBody = scanner.useDelimiter("\\A").next(); System.out.println(responseBody); } 

用查询参数发起HTTP POST请求

URLConnection#setDoOutput()true隐式设置请求方法为POST。 作为web表单的标准HTTP POST是typesapplication/x-www-form-urlencoded其中查询string被写入请求主体。

 URLConnection connection = new URL(url).openConnection(); connection.setDoOutput(true); // Triggers POST. connection.setRequestProperty("Accept-Charset", charset); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset); try (OutputStream output = connection.getOutputStream()) { output.write(query.getBytes(charset)); } InputStream response = connection.getInputStream(); // ... 

注意:只要你想以编程的方式提交一个HTML表单,不要忘记把任何<input type="hidden">元素的name=value对放入查询string中,当然也要把name=value对您希望以编程方式“按下”的<input type="submit">元素(因为通常在服务器端用来区分button是否被按下,如果是,哪一个button被按下)。

您也可以将获取的URLConnectionHttpURLConnection并使用其HttpURLConnection#setRequestMethod()代替。 但是,如果您尝试使用连接输出,则仍然需要将URLConnection#setDoOutput()true

 HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection(); httpConnection.setRequestMethod("POST"); // ... 

无论哪种方式,如果另一端是一个HttpServlet ,那么它的doPost()方法将被调用,参数将由HttpServletRequest#getParameter()


实际上是触发HTTP请求

您可以使用URLConnection#connect()明确地触发HTTP请求,但是当您想获取有关HTTP响应的任何信息(如使用URLConnection#getInputStream()等的响应主体URLConnection#connect() ,请求将自动按需触发。 上面的例子确实如此,所以connect()调用实际上是多余的。


收集HTTP响应信息

  1. HTTP响应状态 :

    你需要一个HttpURLConnection 。 如果有必要,先把它扔掉。

     int status = httpConnection.getResponseCode(); 
  2. HTTP响应标头 :

     for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { System.out.println(header.getKey() + "=" + header.getValue()); } 
  3. HTTP响应编码 :

    Content-Type包含charset参数时,响应主体可能是基于文本的,我们希望用服务器端指定的字符编码来处理响应主体。

     String contentType = connection.getHeaderField("Content-Type"); String charset = null; for (String param : contentType.replace(" ", "").split(";")) { if (param.startsWith("charset=")) { charset = param.split("=", 2)[1]; break; } } if (charset != null) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) { for (String line; (line = reader.readLine()) != null;) { // ... System.out.println(line) ? } } } else { // It's likely binary content, use InputStream/OutputStream. } 

维护会话

服务器端会话通常由一个cookie支持。 一些networking表单要求您login和/或由会话跟踪。 您可以使用CookieHandler API来维护Cookie。 您需要在发送所有HTTP请求之前使用CookiePolicyACCEPT_ALL准备一个CookieManager

 // First set the default cookie manager. CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL)); // All the following subsequent URLConnections will use the same cookie manager. URLConnection connection = new URL(url).openConnection(); // ... connection = new URL(url).openConnection(); // ... connection = new URL(url).openConnection(); // ... 

请注意,这已知在任何情况下都不能正常工作。 如果它失败了,那么最好是手动收集和设置cookie头。 您基本上需要从login响应或第一个GET请求中获取所有Set-Cookie头,然后通过后续请求传递。

 // Gather all cookies on the first request. URLConnection connection = new URL(url).openConnection(); List<String> cookies = connection.getHeaderFields().get("Set-Cookie"); // ... // Then use the same cookies on all subsequent requests. connection = new URL(url).openConnection(); for (String cookie : cookies) { connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]); } // ... 

split(";", 2)[0]是摆脱Cookie的属性,这是不相关的服务器端像expirespath等。或者,也可以使用cookie.substring(0, cookie.indexOf(';'))而不是split()


stream模式

HttpURLConnection在实际发送之前会默认缓冲整个请求体,无论你是否使用connection.setRequestProperty("Content-Length", contentLength);来设置固定的内容长度connection.setRequestProperty("Content-Length", contentLength); 。 这可能会导致OutOfMemoryException s每当你同时发送大的POST请求(例如上传文件)。 为了避免这种情况,你想设置HttpURLConnection#setFixedLengthStreamingMode()

 httpConnection.setFixedLengthStreamingMode(contentLength); 

但是,如果内容长度事先并不知道,那么可以通过相应地设置HttpURLConnection#setChunkedStreamingMode()来使用分块stream模式。 这将设置HTTP Transfer-Encodingchunked ,这将强制请求正在发送块。 下面的例子将以1KB的块forms发送主体。

 httpConnection.setChunkedStreamingMode(1024); 

用户代理

可能会发生请求返回意外的响应,而在真正的Web浏览器中可以正常工作。 服务器端可能会阻止基于User-Agent请求标头的请求。 URLConnection默认将其设置为Java/1.6.0_19 ,最后一部分显然是JRE版本。 你可以覆盖这个如下:

 connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); // Do as if you're using Chrome 41 on Windows 7. 

使用最近浏览器的User-Agentstring。


error handling

如果HTTP响应代码是4nn (客户端错误)或5nn (服务器错误),那么您可能需要阅读HttpURLConnection#getErrorStream()以查看服务器是否发送了任何有用的错误信息。

 InputStream error = ((HttpURLConnection) connection).getErrorStream(); 

如果HTTP响应代码是-1,那么连接和响应处理出了问题。 HttpURLConnection实现在较旧的JRE中有一些漏洞,使连接保持活跃状态​​。 您可能希望通过将http.keepAlive系统属性设置为false来closures它。 您可以通过以下方式在应用程序开始时以编程方式执行此操作:

 System.setProperty("http.keepAlive", "false"); 

上传文件

您通常使用multipart/form-data编码混合POST内容(二进制和字符数据)。 编码在RFC2388中有更详细的描述。

 String param = "value"; File textFile = new File("/path/to/file.txt"); File binaryFile = new File("/path/to/file.bin"); String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value. String CRLF = "\r\n"; // Line separator required by multipart/form-data. URLConnection connection = new URL(url).openConnection(); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); try ( OutputStream output = connection.getOutputStream(); PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true); ) { // Send normal param. writer.append("--" + boundary).append(CRLF); writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF); writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); writer.append(CRLF).append(param).append(CRLF).flush(); // Send text file. writer.append("--" + boundary).append(CRLF); writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF); writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset! writer.append(CRLF).flush(); Files.copy(textFile.toPath(), output); output.flush(); // Important before continuing with writer! writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary. // Send binary file. writer.append("--" + boundary).append(CRLF); writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF); writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF); writer.append("Content-Transfer-Encoding: binary").append(CRLF); writer.append(CRLF).flush(); Files.copy(binaryFile.toPath(), output); output.flush(); // Important before continuing with writer! writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary. // End of multipart/form-data. writer.append("--" + boundary + "--").append(CRLF).flush(); } 

如果另一端是一个HttpServlet ,那么它的doPost()方法将被调用,并且这些部分将由HttpServletRequest#getPart() (注意,因此不是 getParameter()HttpServletRequest#getPart()可用。 然而, getPart()方法相对较新,在Servlet 3.0(GlassFish 3,Tomcat 7等)中引入。 在Servlet 3.0之前,最好的select是使用Apache Commons FileUploadparsingmultipart/form-data请求。 另请参阅FileUpload和Servelt 3.0方法的示例。


处理不可信或错误configuration的HTTPS站点

有时你需要连接一个HTTPS的URL,也许是因为你正在写一个网页抓取工具。 在这种情况下,您可能会遇到一个javax.net.ssl.SSLException: Not trusted server certificate某些HTTPS站点上的javax.net.ssl.SSLException: Not trusted server certificate ,它们未保持最新的SSL证书或java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] foundjavax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name某些configuration错误的HTTPS站点上的javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name

以下一次性运行在您的网页刮板类中的static初始值设定程序应使HttpsURLConnection对这些HTTPS网站更为宽松,从而不会再抛出这些exception。

 static { TrustManager[] trustAllCertificates = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; // Not relevant. } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { // Do nothing. Just allow them all. } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { // Do nothing. Just allow them all. } } }; HostnameVerifier trustAllHostnames = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; // Just allow them all. } }; try { System.setProperty("jsse.enableSNIExtension", "false"); SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCertificates, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames); } catch (GeneralSecurityException e) { throw new ExceptionInInitializerError(e); } } 

最后的话

Apache的HttpComponents HttpClient在这方面是更方便:)

  • HttpClient教程
  • HttpClient示例

parsing和提取HTML

如果你只想从HTMLparsing和提取数据,那么最好使用像Jsoup这样的HTMLparsing器

  • Java中领先的HTMLparsing器有什么优点/缺点?
  • 如何在Java中扫描和提取网页

在使用HTTP时,引用HttpURLConnection而不是基类URLConnection几乎总是更有用(因为当您在HTTP URL上请求URLConnection.openConnection()时, URLConnection是一个抽象类)。

然后,你可以不依赖于URLConnection#setDoOutput(true)来隐式设置请求方法为POST,而是执行httpURLConnection.setRequestMethod("POST") ,有些人可能会发现更自然(也允许你指定其他请求方法,如PUTDELETE ,…)。

它也提供了有用的HTTP常量,所以你可以这样做:

 int responseCode = httpURLConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { 

受到这个和其他问题的启发,我创build了一个最小的开源的基本http客户端 ,体现了这里发现的大部分技术。

google-http-java-client也是一个很好的开源资源。

有2个选项可以使用HTTP URL点击:GET / POST

GET请求: –

 HttpURLConnection.setFollowRedirects(true); // defaults to true String url = "https://name_of_the_url"; URL request_url = new URL(url); HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection(); http_conn.setConnectTimeout(100000); http_conn.setReadTimeout(100000); http_conn.setInstanceFollowRedirects(true); System.out.println(String.valueOf(http_conn.getResponseCode())); 

POST请求: –

 HttpURLConnection.setFollowRedirects(true); // defaults to true String url = "https://name_of_the_url" URL request_url = new URL(url); HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection(); http_conn.setConnectTimeout(100000); http_conn.setReadTimeout(100000); http_conn.setInstanceFollowRedirects(true); http_conn.setDoOutput(true); PrintWriter out = new PrintWriter(http_conn.getOutputStream()); if (urlparameter != null) { out.println(urlparameter); } out.close(); out = null; System.out.println(String.valueOf(http_conn.getResponseCode())); 

我也很受这个回应的启发。

我经常在需要做一些HTTP的项目上,而且我可能不想引入大量的第三方依赖项(引入其他内容等等)

我开始根据这些谈话编写我自己的实用程序(不是在哪里完成的):

 package org.boon.utils; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Map; import static org.boon.utils.IO.read; public class HTTP { 

那么只是一堆或静态的方法。

 public static String get( final String url) { Exceptions.tryIt(() -> { URLConnection connection; connection = doGet(url, null, null, null); return extractResponseString(connection); }); return null; } public static String getWithHeaders( final String url, final Map<String, ? extends Object> headers) { URLConnection connection; try { connection = doGet(url, headers, null, null); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } public static String getWithContentType( final String url, final Map<String, ? extends Object> headers, String contentType) { URLConnection connection; try { connection = doGet(url, headers, contentType, null); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } public static String getWithCharSet( final String url, final Map<String, ? extends Object> headers, String contentType, String charSet) { URLConnection connection; try { connection = doGet(url, headers, contentType, charSet); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } 

然后发布…

 public static String postBody( final String url, final String body) { URLConnection connection; try { connection = doPost(url, null, "text/plain", null, body); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } public static String postBodyWithHeaders( final String url, final Map<String, ? extends Object> headers, final String body) { URLConnection connection; try { connection = doPost(url, headers, "text/plain", null, body); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } public static String postBodyWithContentType( final String url, final Map<String, ? extends Object> headers, final String contentType, final String body) { URLConnection connection; try { connection = doPost(url, headers, contentType, null, body); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } public static String postBodyWithCharset( final String url, final Map<String, ? extends Object> headers, final String contentType, final String charSet, final String body) { URLConnection connection; try { connection = doPost(url, headers, contentType, charSet, body); return extractResponseString(connection); } catch (Exception ex) { Exceptions.handle(ex); return null; } } private static URLConnection doPost(String url, Map<String, ? extends Object> headers, String contentType, String charset, String body ) throws IOException { URLConnection connection;/* Handle output. */ connection = new URL(url).openConnection(); connection.setDoOutput(true); manageContentTypeHeaders(contentType, charset, connection); manageHeaders(headers, connection); IO.write(connection.getOutputStream(), body, IO.CHARSET); return connection; } private static void manageHeaders(Map<String, ? extends Object> headers, URLConnection connection) { if (headers != null) { for (Map.Entry<String, ? extends Object> entry : headers.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue().toString()); } } } private static void manageContentTypeHeaders(String contentType, String charset, URLConnection connection) { connection.setRequestProperty("Accept-Charset", charset == null ? IO.CHARSET : charset); if (contentType!=null && !contentType.isEmpty()) { connection.setRequestProperty("Content-Type", contentType); } } private static URLConnection doGet(String url, Map<String, ? extends Object> headers, String contentType, String charset) throws IOException { URLConnection connection;/* Handle output. */ connection = new URL(url).openConnection(); manageContentTypeHeaders(contentType, charset, connection); manageHeaders(headers, connection); return connection; } private static String extractResponseString(URLConnection connection) throws IOException { /* Handle input. */ HttpURLConnection http = (HttpURLConnection)connection; int status = http.getResponseCode(); String charset = getCharset(connection.getHeaderField("Content-Type")); if (status==200) { return readResponseBody(http, charset); } else { return readErrorResponseBody(http, status, charset); } } private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) { InputStream errorStream = http.getErrorStream(); if ( errorStream!=null ) { String error = charset== null ? read( errorStream ) : read( errorStream, charset ); throw new RuntimeException("STATUS CODE =" + status + "\n\n" + error); } else { throw new RuntimeException("STATUS CODE =" + status); } } private static String readResponseBody(HttpURLConnection http, String charset) throws IOException { if (charset != null) { return read(http.getInputStream(), charset); } else { return read(http.getInputStream()); } } private static String getCharset(String contentType) { if (contentType==null) { return null; } String charset = null; for (String param : contentType.replace(" ", "").split(";")) { if (param.startsWith("charset=")) { charset = param.split("=", 2)[1]; break; } } charset = charset == null ? IO.CHARSET : charset; return charset; } 

那么你的想法….

这里是testing:

 static class MyHandler implements HttpHandler { public void handle(HttpExchange t) throws IOException { InputStream requestBody = t.getRequestBody(); String body = IO.read(requestBody); Headers requestHeaders = t.getRequestHeaders(); body = body + "\n" + copy(requestHeaders).toString(); t.sendResponseHeaders(200, body.length()); OutputStream os = t.getResponseBody(); os.write(body.getBytes()); os.close(); } } @Test public void testHappy() throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(9212), 0); server.createContext("/test", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); Thread.sleep(10); Map<String,String> headers = map("foo", "bar", "fun", "sun"); String response = HTTP.postBodyWithContentType("http://localhost:9212/test", headers, "text/plain", "hi mom"); System.out.println(response); assertTrue(response.contains("hi mom")); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); response = HTTP.postBodyWithCharset("http://localhost:9212/test", headers, "text/plain", "UTF-8", "hi mom"); System.out.println(response); assertTrue(response.contains("hi mom")); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); response = HTTP.postBodyWithHeaders("http://localhost:9212/test", headers, "hi mom"); System.out.println(response); assertTrue(response.contains("hi mom")); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); response = HTTP.get("http://localhost:9212/test"); System.out.println(response); response = HTTP.getWithHeaders("http://localhost:9212/test", headers); System.out.println(response); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); response = HTTP.getWithContentType("http://localhost:9212/test", headers, "text/plain"); System.out.println(response); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); response = HTTP.getWithCharSet("http://localhost:9212/test", headers, "text/plain", "UTF-8"); System.out.println(response); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); Thread.sleep(10); server.stop(0); } @Test public void testPostBody() throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(9220), 0); server.createContext("/test", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); Thread.sleep(10); Map<String,String> headers = map("foo", "bar", "fun", "sun"); String response = HTTP.postBody("http://localhost:9220/test", "hi mom"); assertTrue(response.contains("hi mom")); Thread.sleep(10); server.stop(0); } @Test(expected = RuntimeException.class) public void testSad() throws Exception { HttpServer server = HttpServer.create(new InetSocketAddress(9213), 0); server.createContext("/test", new MyHandler()); server.setExecutor(null); // creates a default executor server.start(); Thread.sleep(10); Map<String,String> headers = map("foo", "bar", "fun", "sun"); String response = HTTP.postBodyWithContentType("http://localhost:9213/foo", headers, "text/plain", "hi mom"); System.out.println(response); assertTrue(response.contains("hi mom")); assertTrue(response.contains("Fun=[sun], Foo=[bar]")); Thread.sleep(10); server.stop(0); } 

你可以在这里find其余的:

https://github.com/RichardHightower/boon

我的目标是提供一个更容易的方法,然后再做一些常见的事情….

我build议你看看kevinsawicki / http-request上的代码,它基本上是HttpUrlConnection上的一个包装器,它提供了一个更简单的API,以防止你现在只需要创build请求,或者你可以看看源代码(这不是太大)来看看如何处理连接。

示例:使用内容typesapplication/json和一些查询参数进行GET请求:

 // GET http://google.com?q=baseball%20gloves&size=100 String response = HttpRequest.get("http://google.com", true, "q", "baseball gloves", "size", 100) .accept("application/json") .body(); System.out.println("Response was: " + response); 

最初我被这篇赞成HttpClient 文章误导了。

后来我已经意识到HttpURLConnection将会停留在这篇文章中

根据Google博客

Apache HTTP客户端在Eclair和Froyo上有更less的错误。 这是这些版本的最佳select。 对于姜饼,HttpURLConnection是最好的select。 其简单的API和小尺寸使其非常适合Android。

透明压缩和响应caching减lessnetworking使用,提高速度并节省电池。 新的应用程序应该使用HttpURLConnection; 这是我们将在哪里花费我们的能量前进。

在阅读本文和其他一些关于stream程问题的堆栈之后,我确信HttpURLConnection将持续更长的时间。

一些有利于HttpURLConnections的SE问题:

在Android上,使用URL编码表单数据进行POST请求,而不使用UrlEncodedFormEntity

HttpPost在Java项目中工作,而不是在Android中

你也可以使用JdkRequest -http (我是一个开发者)的JdkRequest ,它为你完成所有这些工作,装饰HttpURLConnection,触发HTTP请求和parsing响应,例如:

 String html = new JdkRequest("http://www.google.com").fetch().body(); 

查看这个博客文章的更多信息: http : //www.yegor256.com/2014/04/11/jcabi-http-intro.html

在Java 9中,您可以发送GET请求,如:

 // GET HttpResponse response = HttpRequest .create(new URI("http://www.stackoverflow.com")) .headers("Foo", "foovalue", "Bar", "barvalue") .GET() .response(); 

然后你可以检查返回的HttpResponse

 int statusCode = response.statusCode(); String responseBody = response.body(HttpResponse.asString()); 

由于这个新的HTTP客户端在java.httpclient模块中,所以你应该在你的module-info.java文件中声明这个依赖:

 module com.foo.bar { requires java.httpclient; } 

还有OkHttp ,这是一个默认有效的HTTP客户端:

  • HTTP / 2支持允许同一主机的所有请求共享一个套接字。
  • 连接池可减less请求延迟(如果HTTP / 2不可用)。
  • 透明的GZIP缩小下载大小。
  • 响应caching避免了完全重复请求的networking。

首先创build一个OkHttpClient的实例:

 OkHttpClient client = new OkHttpClient(); 

然后,准备您的GET请求:

 Request request = new Request.Builder() .url(url) .build(); 

最后,使用OkHttpClient发送准备好的Request

 Response response = client.newCall(request).execute(); 

有关更多详细信息,请参阅OkHttp的文档

如果你使用http get请删除这行urlConnection.setDoOutput(true);

我推荐build立在apache http api上的http-request 。 (我是开发者)

执行HTTP GET请求

 static final HttpRequest<String> httpRequest = HttpRequestBuilder.createGet(someUri, String.class) .responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build(); ResponseHandler<String> responseHandler = httpRequest.execute(requestParameters); int statusCode = responseHandler.getStatusCode(); String responseBody = responseHandler.get(); // see javadoc of get method 

要么

  ResponseHandler<String> responseHandler = httpRequest.executeWithQuery(queryString); //queryString example "param1=param1&param2=param2" 

执行HTTP POST请求

HttpRequestBuilder.createGetreplace为HttpRequestBuilder.createPost

添加标题

 static final HttpRequest<String> httpRequest = HttpRequestBuilder.createGet(someUri, String.class) .responseDeserializer(ResponseDeserializer.ignorableDeserializer()) .addDefaultHeader("Accept", "application/json") .build(); 

将响应转换为types

让我们说,回应是JSON,你知道

{"name":"myname","lastname":"mylastname","age":25}

您必须创build类User:

 public User{ private String Name; private String Lastname; private int Age; // getters and setters } static final HttpRequest<User> httpRequest = HttpRequestBuilder.createGet(someUri, User.class).build(); ResponseHandler<User> responseHandler = httpRequest.execute(requestParameters); User userFromResponse = responseHandler.orElse(null); //returns null if content isn't present System.out.print(user.getName()); //myname 

注意:您不必担心exception。 所有exception都被包装。