编辑:现在我已经发现了一些行为,我想知道,为什么不会在我打电话后立即发送请求flush()
?还是close()
?为什么要等到我致电getResponseCode()
?
原始问题:
我是java中的HttpsURLConnection类的新手,并查看了doc并发现它不是很有启发性。我在我正在处理的项目上继承了这段代码(我自己没有写过),并想知道它在做什么,以及如何改进它。例如,我无法判断" writeBytes"实际上发送数据或"关闭。"我查看过很多javadoc并发现它们含糊不清,并且在网上的书籍或博客文章中找不到任何有关此主题的好资源。有人可以赐教,或者给我一些好的资源吗?
顺便说一下,这段代码适用于我正在处理的Android SDK库。
注意:我非常了解HTTP请求的理论。我上课了。我知道所有关于URL参数(使用?name = value)和cookie以及RESTful服务以及TCP和IP ......等等。只是努力寻找好的文档,所以我知道如何使用java库。
编辑:将此更改为HttpClient代码,因为事实证明我无法使用Https并仍然可以看到来自echo服务器的请求。它有同样的想法。
import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class HttpClient
{
public static final String DEBUG_URL = "http://10.20.1.61:8001/api/ad/v5/";
public static final String MAPPED_KEYWORDS = "get_mapped_keywords/";
private static byte[] buffer = new byte[1024];
static NetworkReturn sendHttpPost(String urlString, String postData)
{
URL url;
HttpURLConnection con = null;
try {
url = new URL(urlString);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(postData.length()));
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(postData);
output.close();
StringBuilder result = new StringBuilder(), error = new StringBuilder();
int responseCode = con.getResponseCode();
if (responseCode >= 200 && responseCode < 300)
{
if (con.getInputStream() != null)
{
InputStream in = new BufferedInputStream(con.getInputStream());
int length;
while ((length = in.read(buffer)) != -1)
{
result.append(new String(buffer, 0, length));
}
}
}
else
{
if (con.getErrorStream() != null)
{
InputStream in = new BufferedInputStream(con.getErrorStream());
int length;
while ((length = in.read(buffer)) != -1)
{
error.append(new String(buffer, 0, length));
}
}
}
return new NetworkReturn(responseCode, result.toString(), error.toString());
}
catch (MalformedURLException e) {
return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
}
catch (IOException e) {
e.printStackTrace();
return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
}
finally {
if (con != null)
con.disconnect();
}
}
}
答案 0 :(得分:2)
您调用的第一个从服务器获取输入的方法将设置content-length标头并写入输出。这可能是getResponseCode()或getInputStream(),也可能是getErrorStream()。
如果您使用固定长度或分块传输模式,则直接写入。
答案 1 :(得分:1)
例如,我无法判断“writeBytes”是否实际发送数据或 “关闭”。
这有点模棱两可,无法提供实施余地。
问题在于是否使用固定长度或分块请求。默认情况下似乎正在使用固定长度请求,尽管规范不需要它。可以通过HttpURLConnection上的方法控制行为。要指定chunked的使用,您可以致电setChunkedStreamingMode。您也可以调用setFixedLengthStreamingMode来定义请求的固定长度。即使在这种情况下,实现/可以/选择尽早开始发送数据,因为总长度是已知的,因此可以在请求头中正确设置。
实际上,调用writeBytes
将(通常)导致数据缓冲,直到达到某个阈值。那时缓冲的数据将被实际写入并且过程将重复。当您调用close
时,将写入任何缓冲的数据以及表示http请求结束的必要字节。
对flush
的显式调用通常也会导致写出任何缓冲数据。
答案 2 :(得分:0)
我终于明白了。 &#34; getResponseCode()&#34;方法是打破骆驼背部的稻草(可以这么说)。因为当我评论出来的东西时,就是当我评论它的一部分时,它没有回复&#34;我在使用的echo服务器上的响应(并将收到的请求打印到终端)。
注意:我使用了几乎相同的HttpClient类,否则echo服务器会打印出这样的加密代码:
����5D��s����l!���RMav* X?�+gJ.�+�/��32E98�/A5�P localhost�
当我将此代码作为Java应用程序运行时,服务器没有向终端打印任何内容: (注意注释掉的部分)
static NetworkReturn sendHttpPost(String urlString, String postData)
{
URL url;
HttpURLConnection con = null;
try {
url = new URL(urlString);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(postData.length()));
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(postData);
output.close();
//StringBuilder result = new StringBuilder(), error = new StringBuilder();
//int responseCode = con.getResponseCode();
/*
if (responseCode >= 200 && responseCode < 300)
{
if (con.getInputStream() != null)
{
InputStream in = new BufferedInputStream(con.getInputStream());
int length;
while ((length = in.read(buffer)) != -1)
{
result.append(new String(buffer, 0, length));
}
}
}
else
{
if (con.getErrorStream() != null)
{
InputStream in = new BufferedInputStream(con.getErrorStream());
int length;
while ((length = in.read(buffer)) != -1)
{
error.append(new String(buffer, 0, length));
}
}
}
return new NetworkReturn(responseCode, result.toString(), error.toString());
*/
return new NetworkReturn();
}
catch (MalformedURLException e) {
return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
}
catch (IOException e) {
e.printStackTrace();
return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
}
finally {
if (con != null)
con.disconnect();
}
}
但是,此代码DID使服务器打印到终端:
static NetworkReturn sendHttpPost(String urlString, String postData)
{
URL url;
HttpURLConnection con = null;
try {
url = new URL(urlString);
con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-length", String.valueOf(postData.length()));
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(postData);
output.close();
//StringBuilder result = new StringBuilder(), error = new StringBuilder();
int responseCode = con.getResponseCode();
/*
if (responseCode >= 200 && responseCode < 300)
{
if (con.getInputStream() != null)
{
InputStream in = new BufferedInputStream(con.getInputStream());
int length;
while ((length = in.read(buffer)) != -1)
{
result.append(new String(buffer, 0, length));
}
}
}
else
{
if (con.getErrorStream() != null)
{
InputStream in = new BufferedInputStream(con.getErrorStream());
int length;
while ((length = in.read(buffer)) != -1)
{
error.append(new String(buffer, 0, length));
}
}
}
return new NetworkReturn(responseCode, result.toString(), error.toString());
*/
return new NetworkReturn();
}
catch (MalformedURLException e) {
return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
}
catch (IOException e) {
e.printStackTrace();
return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
}
finally {
if (con != null)
con.disconnect();
}
}
并且终端输出是这个(回显服务器,所以这是请求必须看起来像的那样):
POST / HTTP/1.1 Content-Type: application/json User-Agent: Java/1.7.0_60 Host: localhost:3000 Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 Connection: keep-alive Content-Length: 16 blah blah blah
这是我做的方法调用:
public class Main
{
public static void main(String[] args)
{
NetworkReturn result = HttpClient.sendHttpPost("http://localhost:3000/", "blah blah blah\n\n");
}
}
修改强> 我通过向输出流调用flush来尝试Brett的建议(getResponseCode()仍然被注释掉,所以现在我看到flush是否会使它工作):
...
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(postData);
output.flush(); //<------------here
output.close();
//StringBuilder result = new StringBuilder(), error = new StringBuilder();
//int responseCode = con.getResponseCode();
/*
if (responseCode >= 200 && responseCode < 300)
{
if
...
但我的echo服务器没有打印任何东西。这是有道理的,现在我考虑一下,因为&#34; output.close();&#34;可能会调用&#34; flush()&#34;已经。如果flush()工作,那么我的第一个代码片段(带有getResponseCode()注释掉)可能会有效。
编辑:试图查看512千字节的请求正文是否会产生差异并导致请求被发送,但是当getResponseCode()
被注释掉时,它无法正常工作。当我取消注释getResponseCode()
时,我确认它有效。
我测试大型&#34;文件的新主要方法&#34;,假设char是1个字节,所以它应该超过512千字节:
public class Main
{
public static void main(String[] args)
{
StringBuilder largeString = new StringBuilder();
for (int i = 0; i < 524288; i++)
{
largeString.append('a');
}
largeString.append("\n\n");
NetworkReturn result = HttpClient.sendHttpPost("http://localhost:3000/", largeString.toString());
}
}