如何使用 java.net.URLConnection 来触发和处理 HTTP 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2793150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use java.net.URLConnection to fire and handle HTTP requests?
提问by BalusC
Use of java.net.URLConnection
is asked about pretty often here, and the Oracle tutorialis tooconcise about it.
java.net.URLConnection
在这里经常被问到使用的问题,而且Oracle 教程对此过于简洁。
That tutorial basically only shows how to fire a GET request and read the response. It doesn't explain anywhere how to use it to among others perform a POST request, set request headers, read response headers, deal with cookies, submit a HTML form, upload a file, etc.
该教程基本上只展示了如何触发 GET 请求并读取响应。它没有在任何地方解释如何使用它来执行 POST 请求、设置请求标头、读取响应标头、处理 cookie、提交 HTML 表单、上传文件等。
So, how can I use java.net.URLConnection
to fire and handle "advanced" HTTP requests?
那么,我如何使用java.net.URLConnection
来触发和处理“高级”HTTP 请求?
采纳答案by BalusC
First a disclaimer beforehand: the posted code snippets are all basic examples. You'll need to handle trivial IOException
s and RuntimeException
s like NullPointerException
, ArrayIndexOutOfBoundsException
and consorts yourself.
首先事先声明:发布的代码片段都是基本示例。您需要处理琐碎的IOException
s 和RuntimeException
s 之类的事情NullPointerException
,ArrayIndexOutOfBoundsException
并与自己结盟。
Preparing
准备
We first need to know at least the URL and the charset. The parameters are optional and depend on the functional requirements.
我们首先至少需要知道 URL 和字符集。这些参数是可选的,取决于功能要求。
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¶m2=%s",
URLEncoder.encode(param1, charset),
URLEncoder.encode(param2, charset));
The query parameters must be in name=value
format and be concatenated by &
. You would normally also URL-encodethe query parameters with the specified charset using URLEncoder#encode()
.
查询参数必须采用name=value
格式并由 连接&
。通常,您还可以使用指定的字符集对查询参数进行 URL 编码URLEncoder#encode()
。
The String#format()
is just for convenience. I prefer it when I would need the String concatenation operator +
more than twice.
该String#format()
只是为方便起见。当我需要+
两次以上的字符串连接运算符时,我更喜欢它。
Firing a HTTP GETrequest with (optionally) query parameters
使用(可选)查询参数触发HTTP GET请求
It's a trivial task. It's the default request method.
这是一项微不足道的任务。这是默认的请求方法。
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
Any query string should be concatenated to the URL using ?
. The Accept-Charset
header may hint the server what encoding the parameters are in. If you don't send any query string, then you can leave the Accept-Charset
header away. If you don't need to set any headers, then you can even use the URL#openStream()
shortcut method.
任何查询字符串都应使用 连接到 URL ?
。该Accept-Charset
标题可能暗示什么编码参数是在服务器中。如果你不发送任何查询字符串,那么你就可以离开了Accept-Charset
头了。如果您不需要设置任何标题,那么您甚至可以使用URL#openStream()
快捷方式。
InputStream response = new URL(url).openStream();
// ...
Either way, if the other side is a HttpServlet
, then its doGet()
method will be called and the parameters will be available by HttpServletRequest#getParameter()
.
无论哪种方式,如果另一方是 a HttpServlet
,那么它的doGet()
方法将被调用并且参数将由HttpServletRequest#getParameter()
.
For testing purposes, you can print the response body to stdout as below:
出于测试目的,您可以将响应正文打印到标准输出,如下所示:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\A").next();
System.out.println(responseBody);
}
Firing a HTTP POSTrequest with query parameters
使用查询参数触发HTTP POST请求
Setting the URLConnection#setDoOutput()
to true
implicitly sets the request method to POST. The standard HTTP POST as web forms do is of type application/x-www-form-urlencoded
wherein the query string is written to the request body.
将 设置URLConnection#setDoOutput()
为true
隐式将请求方法设置为 POST。Web 表单所做的标准 HTTP POST 属于application/x-www-form-urlencoded
将查询字符串写入请求正文的类型。
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();
// ...
Note: whenever you'd like to submit a HTML form programmatically, don't forget to take the name=value
pairs of any <input type="hidden">
elements into the query string and of course also the name=value
pair of the <input type="submit">
element which you'd like to "press" programmatically (because that's usually been used in the server side to distinguish if a button was pressed and if so, which one).
注意:每当您想以编程方式提交 HTML 表单时,不要忘记将name=value
任何<input type="hidden">
元素对带入查询字符串,当然还有您想以编程方式“按下”name=value
的<input type="submit">
元素对(因为这通常用于服务器端来区分按钮是否被按下,如果按下,是哪个)。
You can also cast the obtained URLConnection
to HttpURLConnection
and use its HttpURLConnection#setRequestMethod()
instead. But if you're trying to use the connection for output you still need to set URLConnection#setDoOutput()
to true
.
您还可以将获得的转换URLConnection
为HttpURLConnection
并使用它HttpURLConnection#setRequestMethod()
。但是,如果您尝试将连接用于输出,您仍然需要设置URLConnection#setDoOutput()
为true
.
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
Either way, if the other side is a HttpServlet
, then its doPost()
method will be called and the parameters will be available by HttpServletRequest#getParameter()
.
无论哪种方式,如果另一方是 a HttpServlet
,那么它的doPost()
方法将被调用并且参数将由HttpServletRequest#getParameter()
.
Actually firing the HTTP request
实际触发 HTTP 请求
You can fire the HTTP request explicitly with URLConnection#connect()
, but the request will automatically be fired on demand when you want to get any information about the HTTP response, such as the response body using URLConnection#getInputStream()
and so on. The above examples does exactly that, so the connect()
call is in fact superfluous.
您可以使用 显式触发 HTTP 请求URLConnection#connect()
,但是当您想要获取有关 HTTP 响应的任何信息(例如使用的响应正文等)时,该请求将根据需要自动触发URLConnection#getInputStream()
。上面的例子正是这样做的,所以connect()
调用实际上是多余的。
Gathering HTTP response information
收集 HTTP 响应信息
You need a
HttpURLConnection
here. Cast it first if necessary.int status = httpConnection.getResponseCode();
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { System.out.println(header.getKey() + "=" + header.getValue()); }
When the
Content-Type
contains acharset
parameter, then the response body is likely text based and we'd like to process the response body with the server-side specified character encoding then.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. }
你需要一个
HttpURLConnection
在这里。如有必要,请先施放。int status = httpConnection.getResponseCode();
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { System.out.println(header.getKey() + "=" + header.getValue()); }
当
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. }
Maintaining the session
维护会话
The server side session is usually backed by a cookie. Some web forms require that you're logged in and/or are tracked by a session. You can use the CookieHandler
API to maintain cookies. You need to prepare a CookieManager
with a CookiePolicy
of ACCEPT_ALL
before sending all HTTP requests.
服务器端会话通常由 cookie 支持。某些 Web 表单要求您登录和/或被会话跟踪。您可以使用CookieHandler
API 来维护 cookie。你需要准备一个CookieManager
具有CookiePolicy
中ACCEPT_ALL
发送所有HTTP请求之前。
// 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();
// ...
Note that this is known to not always work properly in all circumstances. If it fails for you, then best is to manually gather and set the cookie headers. You basically need to grab all Set-Cookie
headers from the response of the login or the first GET
request and then pass this through the subsequent requests.
请注意,众所周知,这并不总是在所有情况下都能正常工作。如果它对您来说失败了,那么最好是手动收集和设置 cookie 标头。您基本上需要Set-Cookie
从登录或第一个GET
请求的响应中获取所有标头,然后将其传递给后续请求。
// 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]);
}
// ...
The split(";", 2)[0]
is there to get rid of cookie attributes which are irrelevant for the server side like expires
, path
, etc. Alternatively, you could also use cookie.substring(0, cookie.indexOf(';'))
instead of split()
.
该split(";", 2)[0]
是有摆脱它们是无关的服务器端如cookie的属性expires
,path
等等。另外,你也可以使用cookie.substring(0, cookie.indexOf(';'))
替代的split()
。
Streaming mode
流媒体模式
The HttpURLConnection
will by default buffer the entirerequest body before actually sending it, regardless of whether you've set a fixed content length yourself using connection.setRequestProperty("Content-Length", contentLength);
. This may cause OutOfMemoryException
s whenever you concurrently send large POST requests (e.g. uploading files). To avoid this, you would like to set the HttpURLConnection#setFixedLengthStreamingMode()
.
HttpURLConnection
默认情况下,将在实际发送之前缓冲整个请求正文,无论您是否使用connection.setRequestProperty("Content-Length", contentLength);
. OutOfMemoryException
每当您同时发送大型 POST 请求(例如上传文件)时,这可能会导致s。为避免这种情况,您需要设置HttpURLConnection#setFixedLengthStreamingMode()
.
httpConnection.setFixedLengthStreamingMode(contentLength);
But if the content length is really not known beforehand, then you can make use of chunked streaming mode by setting the HttpURLConnection#setChunkedStreamingMode()
accordingly. This will set the HTTP Transfer-Encoding
header to chunked
which will force the request body being sent in chunks. The below example will send the body in chunks of 1KB.
但是如果内容长度真的事先不知道,那么您可以通过相应地设置来使用分块流模式HttpURLConnection#setChunkedStreamingMode()
。这将设置 HTTPTransfer-Encoding
标头chunked
,将强制请求正文以块的形式发送。下面的示例将以 1KB 的块发送正文。
httpConnection.setChunkedStreamingMode(1024);
User-Agent
用户代理
It can happen that a request returns an unexpected response, while it works fine with a real web browser. The server side is probably blocking requests based on the User-Agent
request header. The URLConnection
will by default set it to Java/1.6.0_19
where the last part is obviously the JRE version. You can override this as follows:
一个请求可能会返回一个意外的响应,而它在真实的 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.
Use the User-Agent string from a recent browser.
使用来自最近浏览器的 User-Agent 字符串。
Error handling
错误处理
If the HTTP response code is 4nn
(Client Error) or 5nn
(Server Error), then you may want to read the HttpURLConnection#getErrorStream()
to see if the server has sent any useful error information.
如果 HTTP 响应代码是4nn
(Client Error) 或5nn
(Server Error),那么您可能需要阅读HttpURLConnection#getErrorStream()
以查看服务器是否发送了任何有用的错误信息。
InputStream error = ((HttpURLConnection) connection).getErrorStream();
If the HTTP response code is -1, then something went wrong with connection and response handling. The HttpURLConnection
implementation is in older JREs somewhat buggy with keeping connections alive. You may want to turn it off by setting the http.keepAlive
system property to false
. You can do this programmatically in the beginning of your application by:
如果 HTTP 响应代码为 -1,则连接和响应处理出现问题。该HttpURLConnection
实现是在较旧的 JRE 中,在保持连接活动方面有些问题。您可能希望通过将http.keepAlive
系统属性设置为 来关闭它false
。您可以通过以下方式在应用程序开始时以编程方式执行此操作:
System.setProperty("http.keepAlive", "false");
Uploading files
上传文件
You'd normally use multipart/form-data
encoding for mixed POST content (binary and character data). The encoding is in more detail described in RFC2388.
您通常会对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();
}
If the other side is a HttpServlet
, then its doPost()
method will be called and the parts will be available by HttpServletRequest#getPart()
(note, thus notgetParameter()
and so on!). The getPart()
method is however relatively new, it's introduced in Servlet 3.0 (Glassfish 3, Tomcat 7, etc). Prior to Servlet 3.0, your best choice is using Apache Commons FileUploadto parse a multipart/form-data
request. Also see this answerfor examples of both the FileUpload and the Servelt 3.0 approaches.
如果另一边是 a HttpServlet
,那么它的doPost()
方法将被调用并且部件将可用HttpServletRequest#getPart()
(注意,因此不是getParameter()
等等!)。getPart()
然而,该方法相对较新,它是在 Servlet 3.0(Glassfish 3、Tomcat 7 等)中引入的。在 Servlet 3.0 之前,最好的选择是使用Apache Commons FileUpload来解析multipart/form-data
请求。有关 FileUpload 和 Servelt 3.0 方法的示例,另请参阅此答案。
Dealing with untrusted or misconfigured HTTPS sites
处理不受信任或配置错误的 HTTPS 站点
Sometimes you need to connect a HTTPS URL, perhaps because you're writing a web scraper. In that case, you may likely face a javax.net.ssl.SSLException: Not trusted server certificate
on some HTTPS sites who doesn't keep their SSL certificates up to date, or a java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
or javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
on some misconfigured HTTPS sites.
有时您需要连接 HTTPS URL,可能是因为您正在编写网络爬虫。在这种情况下,您可能会javax.net.ssl.SSLException: Not trusted server certificate
在某些未将 SSL 证书保持最新的HTTPS 站点上java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
或javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
在某些配置错误的 HTTPS 站点上遇到。
The following one-time-run static
initializer in your web scraper class should make HttpsURLConnection
more lenient as to those HTTPS sites and thus not throw those exceptions anymore.
static
您的网络抓取工具类中的以下一次性运行初始化程序应该HttpsURLConnection
对那些 HTTPS 站点更加宽容,从而不再抛出这些异常。
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);
}
}
Last words
最后的话
The Apache HttpComponents HttpClientis muchmore convenient in this all :)
在Apache的HttpClient的HttpComponents是多少这一切更方便:)
Parsing and extracting HTML
解析和提取 HTML
If all you want is parsing and extracting data from HTML, then better use a HTML parser like Jsoup
如果你想要的只是从 HTML 中解析和提取数据,那么最好使用像Jsoup这样的 HTML 解析器
回答by Paal Thorstensen
When working with HTTP it's almost always more useful to refer to HttpURLConnection
rather than the base class URLConnection
(since URLConnection
is an abstract class when you ask for URLConnection.openConnection()
on a HTTP URL that's what you'll get back anyway).
使用 HTTP 时,引用HttpURLConnection
而不是基类几乎总是更有用URLConnection
(因为URLConnection
当您请求URLConnection.openConnection()
HTTP URL 时,它是一个抽象类,无论如何您都会返回)。
Then you can instead of relying on URLConnection#setDoOutput(true)
to implicitly set the request method to POSTinstead do httpURLConnection.setRequestMethod("POST")
which some might find more natural (and which also allows you to specify other request methods such as PUT, DELETE, ...).
然后,您可以不依赖于URLConnection#setDoOutput(true)
隐式地将请求方法设置为POST而是这样做httpURLConnection.setRequestMethod("POST")
,有些人可能会觉得更自然(并且还允许您指定其他请求方法,例如PUT,DELETE,...)。
It also provides useful HTTP constants so you can do:
它还提供了有用的 HTTP 常量,因此您可以执行以下操作:
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
回答by David Chandler
Inspired by this and other questions on SO, I've created a minimal open source basic-http-clientthat embodies most of the techniques found here.
受此问题和关于 SO 的其他问题的启发,我创建了一个最小的开源basic-http-client,它体现了此处找到的大多数技术。
google-http-java-clientis also a great open source resource.
google-http-java-client也是一个很棒的开源资源。
回答by RickHigh
I was also very inspired by this response.
我也很受这个回应的启发。
I am often on projects where I need to do some HTTP, and I may not want to bring in a lot of 3rd party dependencies (which bring in others and so on and so on, etc.)
我经常在需要做一些 HTTP 的项目中,我可能不想引入很多 3rd 方依赖项(引入其他依赖项等等)
I started to write my own utilities based on some of this conversation (not any where done):
我开始根据这些对话中的一些内容(不是任何地方完成的)编写自己的实用程序:
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 {
Then there are just a bunch or static methods.
然后只有一堆或静态方法。
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;
}
}
Then post...
然后发...
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;
}
Well you get the idea....
反正你懂这个意思....
Here are the tests:
以下是测试:
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);
}
You can find the rest here:
你可以在这里找到其余的:
https://github.com/RichardHightower/boon
https://github.com/RichardHightower/boon
My goal is to provide the common things one would want to do in a bit more easier way then....
我的目标是以更简单的方式提供人们想要做的常见事情......
回答by yegor256
You can also use JdkRequest
from jcabi-http(I'm a developer), which does all this work for you, decorating HttpURLConnection, firing HTTP requests and parsing responses, for example:
您还可以使用JdkRequest
from jcabi-http(我是一名开发人员),它为您完成所有这些工作,装饰 HttpURLConnection、触发 HTTP 请求和解析响应,例如:
String html = new JdkRequest("http://www.google.com").fetch().body();
Check this blog post for more info: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html
查看此博客文章了解更多信息:http: //www.yegor256.com/2014/04/11/jcabi-http-intro.html
回答by fernandohur
I suggest you take a look at the code on kevinsawicki/http-request, its basically a wrapper on top of HttpUrlConnection
it provides a much simpler API in case you just want to make the requests right now or you can take a look at the sources (it's not too big) to take a look at how connections are handled.
我建议您查看kevinsawicki/http-request上的代码,它基本上是HttpUrlConnection
它之上的一个包装器,它提供了一个更简单的 API,以防您只想立即发出请求,或者您可以查看源代码(它不是太大)来看看连接是如何处理的。
Example: Make a GET
request with content type application/json
and some query parameters:
示例:GET
使用内容类型application/json
和一些查询参数发出请求:
// 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);
回答by Utkash Bhatt
There are 2 options you can go with HTTP URL Hits : GET / POST
HTTP URL Hits 有 2 个选项:GET / POST
GET Request :-
获取请求:-
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 request :-
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()));
回答by Ravindra babu
Initially I was misled by this articlewhich favours HttpClient
.
最初我被这篇有利于HttpClient
.
Later I have been realized that HttpURLConnection
is going to stay from this article
后来我意识到HttpURLConnection
要离开这篇文章了
As per the Google blog:
根据谷歌博客:
Apache HTTP client has fewer bugs on Eclair and Froyo. It is the best choice for these releases. For Gingerbread , HttpURLConnection is the best choice. Its simple API and small size makes it great fit for Android.
Transparent compression and response caching reduce network use, improve speed and save battery. New applications should use HttpURLConnection; it is where we will be spending our energy going forward.
Apache HTTP 客户端在 Eclair 和 Froyo 上的错误较少。这是这些版本的最佳选择。对于 Gingerbread , HttpURLConnection 是最佳选择。其简单的 API 和小尺寸使其非常适合 Android。
透明压缩和响应缓存减少网络使用,提高速度并节省电池。新的应用程序应该使用 HttpURLConnection;这是我们今后将花费精力的地方。
After reading this articleand some other stack over flow questions, I am convinced that HttpURLConnection
is going to stay for longer durations.
在阅读了这篇文章和其他一些关于流的堆栈问题后,我相信这HttpURLConnection
会持续更长时间。
Some of the SE questions favouring HttpURLConnections
:
一些偏向于 SE 的问题HttpURLConnections
:
On Android, make a POST request with URL Encoded Form data without using UrlEncodedFormEntity
在 Android 上,使用 URL Encoded Form 数据发出 POST 请求而不使用 UrlEncodedFormEntity
回答by Ali Dehghani
There is also OkHttp, which is an HTTP client that's efficient by default:
还有OkHttp,它是一个默认高效的 HTTP 客户端:
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling reduces request latency (if HTTP/2 isn't available).
- Transparent GZIP shrinks download sizes.
- Response caching avoids the network completely for repeat requests.
- HTTP/2 支持允许对同一主机的所有请求共享一个套接字。
- 连接池减少了请求延迟(如果 HTTP/2 不可用)。
- 透明 GZIP 可缩小下载大小。
- 响应缓存完全避免网络重复请求。
First create an instance of OkHttpClient
:
首先创建一个实例OkHttpClient
:
OkHttpClient client = new OkHttpClient();
Then, prepare your GET
request:
然后,准备您的GET
请求:
Request request = new Request.Builder()
.url(url)
.build();
finally, use OkHttpClient
to send prepared Request
:
最后,使用OkHttpClient
发送准备Request
:
Response response = client.newCall(request).execute();
For more details, you can consult the OkHttp's documentation
更详细的可以参考OkHttp的文档
回答by Nison Cheruvathur
if you are using http get please remove this line
如果您使用的是 http get 请删除此行
urlConnection.setDoOutput(true);