如何使用URLConnection处理http请求
2013-10-18 17:35
274 查看
参考译文:http://lamoop.com/post/2012-08-07/40032367973
一、准备
使用URLConnection操作http request时,我们至少得知道URL地址和字符集,参数是可选的,它基于具体的需求。
参数必须以name=value的形式出现,不同的参数使用&连接,通常还需要用URLEncoder.encode()方法将参数转化为URL编码
String.format()方法是为了方便,如果需要多个 + 来操作字符的时候我就喜欢用这个方法。
二、发送一个带参数(可选)的GET请求
这是一段很简单的代码,使用默认的request方法就行
所有的参数都要放在URL后边,并且使用?连接,头部中的Accept-Charset会告诉服务器你发送的参数使用的是什么编码。如果你不需要发送任何的参数,可以不用写Accept-Charset,如果你不想发送任何的头部信息,可以直接使用URL.openStream()方法。
如果服务器端是HttpServlet,那么它将会调用doGet()方法来处理这个请求,发送的参数可以通过HttpServletRequest.getParameter() 方法访问。
三、发送一个带参数的POST请求
使用URLConnection.setDoOutput(true),就可以发送post请求。网页表单的post请求是application/x-www-form-urlencoded类型的,post请求会将参数放在请求中发送给服务器
Note:如果你要使用程序自动发送一个网页的表单,不要忘了<input type=”hidden” />元素,你要把所有的hidden元素都使用name=value的方法发送给服务器,另外<input type=”submit” />元素也要发送给服务器,因为服务器端通常使用这个参数来判断提交按钮是否被点击,哪一个被点击。
你也可以把URLConnection强制转化为HttpURLConnection,那样的话就可以使用HttpURLConnection.setRequestMethod(“POST”)方法代替URLConnection.setDoOutput(true)了。但是如果你想要从这个连接里获取输入流,那还得使用URLConnection.setDoOutput(true)方法。
如果服务器端是HttpServlet,那么它将调用doPost方法来处理这个请求,发送的参数可以使用HttpServletRequest.getParameter() 方法访问。
四、手动发起HTTP请求
你可以使用URLConnection.connect()方法手动的发送一个http请求,但是如果要获取http响应的时候,请求就会自动的发起,比如你使用URLConnection.getInputStream()方法的时候。上边的例子就是这样做的,所以完全没有必要调用connect方法。
五、获取HTTP响应信息
1)HTTP响应状态
获取HTTP响应状态必须使用HttpURLConnection,所以你的先进行强制转化
2)HTTP响应头部
3)HTTP响应的编码方式
如果Content-Type包含一个charset参数,那么HTTP的响应很可能是文本流,我们就得使用服务器指定的字符集来处理这些文本。
六、维持session状态
服务器端的session通常是使用cookie实现的,网站就是通过追踪session来判断你的登录状态的。你可以通过内置的CookieHandler完成这个任务,在发送HTTP请求之前,你需要来建立一个CookieManager对象,建立对象时会用到CookiePolicy.ACCEPT_ALL。
NOTE:大家都知道上面的代码并不是在所有情况下都运行正常。如果失败了,我们最好手动收集和设置的cookie头。我们需要从登录或者第一次发起GET请求时的响应抓取所有的Set-Cookie头。然后后续请求就可以通过了。
split(“;”, 2)[0]是为了丢掉一些服务器端用不到的属性,比如过期时间,存储路径等。另外你也可以使用cookie.substring(0, cookie.indexOf(';'))代替split()。
七、流模式
在请求发送之前,HttpURLConnetion会把所有需要发送的数据放到缓冲区里,不管你是否使用connection.setRequestProperty("Content-Length", contentLength);设置了contentLength,当你并行发送大量的POST请求时,这可能会引起OutOfMemoryExceptions 异常,为了避免这个问题,你需要使用HttpURLConnection.setFixedLengthStreamingMode()方法。
但是如果不能事先知道内容的长度,可以使用HttpURLConnection.setChunkedStreamingMode()方法设置为块状流模式。在块状流模式的情况下,放在块里的内容将会被强行发送出去。下边的例子将会把发送的内容按照每块1KB的大小发送出去。
八、User-Agent
有的时候发送一个请求,却返回了不期望的响应,但是这个请求在浏览器上却能正常工作。这很可能是服务器做了一些关于基于
九、处理错误
如果HTTP响应状态为4xx(客户端错误)或者5xx(服务器错误),你可以通过HttpUrlConnection.getErrorStream()来查看服务器发送过来的信息。
如果HTTP响应状态为-1,就是出现了连接或者响应错误。HttpURLConnection会保持连接一直可用,如果你想关闭这个特性,需要把http.keepAlive设置为false:
十、上传文件
通常使用multipart/form-data方式对混合了二进制和字符的POST内容进行编码,详细的编码细节可以参考RFC2388。
如果服务器端是HttpServlet,那么它将会调用doPost()方法处理这个请求,使用HttpServletRequest.getPart()方法访问里边的内容(不是getParameter)。getPart方法在Servlet3.0(Glassfish3,Tomcat7)才被引入,在Servlet3.0之前,最好使用Apache Commons
FileUpload 来处理multipart/form-data请求。
结束语
Apache
HttpComponents HttpClient是很方便的处理http请求。
HttpClient
Tutorial
HttpClient
Examples
解析和提取HTML页面
解析HTML最好使用Jsoup。
What
are the pros/cons of leading HTML parsers in Java
How
to scan and extract a webpage in Java
原文来自:StackOverFlow
一、准备
使用URLConnection操作http request时,我们至少得知道URL地址和字符集,参数是可选的,它基于具体的需求。
String url = "http://example.com"; String charset = "UTF-8"; String param1 = "value1"; String param2 = "value2"; // ... String query = String.format("param1=%s¶m2=%s", URLEncoder.encode(param1, charset), URLEncoder.encode(param2, charset));
参数必须以name=value的形式出现,不同的参数使用&连接,通常还需要用URLEncoder.encode()方法将参数转化为URL编码
String.format()方法是为了方便,如果需要多个 + 来操作字符的时候我就喜欢用这个方法。
二、发送一个带参数(可选)的GET请求
这是一段很简单的代码,使用默认的request方法就行
URLConnection connection = new URL(url + "?" + query).openConnection(); connection.setRequestProperty("Accept-Charset", charset); InputStream response = connection.getInputStream(); // ...
所有的参数都要放在URL后边,并且使用?连接,头部中的Accept-Charset会告诉服务器你发送的参数使用的是什么编码。如果你不需要发送任何的参数,可以不用写Accept-Charset,如果你不想发送任何的头部信息,可以直接使用URL.openStream()方法。
InputStream response = new URL(url).openStream(); // ...
如果服务器端是HttpServlet,那么它将会调用doGet()方法来处理这个请求,发送的参数可以通过HttpServletRequest.getParameter() 方法访问。
三、发送一个带参数的POST请求
使用URLConnection.setDoOutput(true),就可以发送post请求。网页表单的post请求是application/x-www-form-urlencoded类型的,post请求会将参数放在请求中发送给服务器
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); OutputStream output = connection.getOutputStream(); try { output.write(query.getBytes(charset)); } finally { try { output.close(); } catch (IOException logOrIgnore) {} } InputStream response = connection.getInputStream(); // ...
Note:如果你要使用程序自动发送一个网页的表单,不要忘了<input type=”hidden” />元素,你要把所有的hidden元素都使用name=value的方法发送给服务器,另外<input type=”submit” />元素也要发送给服务器,因为服务器端通常使用这个参数来判断提交按钮是否被点击,哪一个被点击。
你也可以把URLConnection强制转化为HttpURLConnection,那样的话就可以使用HttpURLConnection.setRequestMethod(“POST”)方法代替URLConnection.setDoOutput(true)了。但是如果你想要从这个连接里获取输入流,那还得使用URLConnection.setDoOutput(true)方法。
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection(); httpConnection.setRequestMethod("POST"); // ...
如果服务器端是HttpServlet,那么它将调用doPost方法来处理这个请求,发送的参数可以使用HttpServletRequest.getParameter() 方法访问。
四、手动发起HTTP请求
你可以使用URLConnection.connect()方法手动的发送一个http请求,但是如果要获取http响应的时候,请求就会自动的发起,比如你使用URLConnection.getInputStream()方法的时候。上边的例子就是这样做的,所以完全没有必要调用connect方法。
五、获取HTTP响应信息
1)HTTP响应状态
获取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参数,那么HTTP的响应很可能是文本流,我们就得使用服务器指定的字符集来处理这些文本。
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) { BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset)); try { for (String line; (line = reader.readLine()) != null;) { // ... System.out.println(line) ? } } finally { try { reader.close(); } catch (IOException logOrIgnore) {} } } else { // It's likely binary content, use InputStream/OutputStream. }
六、维持session状态
服务器端的session通常是使用cookie实现的,网站就是通过追踪session来判断你的登录状态的。你可以通过内置的CookieHandler完成这个任务,在发送HTTP请求之前,你需要来建立一个CookieManager对象,建立对象时会用到CookiePolicy.ACCEPT_ALL。
// 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:大家都知道上面的代码并不是在所有情况下都运行正常。如果失败了,我们最好手动收集和设置的cookie头。我们需要从登录或者第一次发起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.substring(0, cookie.indexOf(';'))代替split()。
七、流模式
在请求发送之前,HttpURLConnetion会把所有需要发送的数据放到缓冲区里,不管你是否使用connection.setRequestProperty("Content-Length", contentLength);设置了contentLength,当你并行发送大量的POST请求时,这可能会引起OutOfMemoryExceptions 异常,为了避免这个问题,你需要使用HttpURLConnection.setFixedLengthStreamingMode()方法。
httpConnection.setFixedLengthStreamingMode(contentLength);
但是如果不能事先知道内容的长度,可以使用HttpURLConnection.setChunkedStreamingMode()方法设置为块状流模式。在块状流模式的情况下,放在块里的内容将会被强行发送出去。下边的例子将会把发送的内容按照每块1KB的大小发送出去。
httpConnection.setChunkedStreamingMode(1024);
八、User-Agent
有的时候发送一个请求,却返回了不期望的响应,但是这个请求在浏览器上却能正常工作。这很可能是服务器做了一些关于基于
User-Agent的判断。URLConnection默认将User-Agent设置为Java/1.6.0_19(后半部分是jre版本),你可以通过下边的方法重新设置:
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401"); // Do as if you're using Firefox 3.6.3.
九、处理错误
如果HTTP响应状态为4xx(客户端错误)或者5xx(服务器错误),你可以通过HttpUrlConnection.getErrorStream()来查看服务器发送过来的信息。
InputStream error = ((HttpURLConnection) connection).getErrorStream();
如果HTTP响应状态为-1,就是出现了连接或者响应错误。HttpURLConnection会保持连接一直可用,如果你想关闭这个特性,需要把http.keepAlive设置为false:
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); PrintWriter writer = null; try { OutputStream output = connection.getOutputStream(); writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true = autoFlush, important! // 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); writer.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); writer.append(CRLF).flush(); BufferedReader reader = new BufferedReader(new InputStreamReader( new FileInputStream(textFile), charset)); try { for (String line; (line = reader.readLine()) != null;) { writer.append(line).append(CRLF); } } finally { try { reader.close(); } catch (IOException logOrIgnore) {} } writer.flush(); // 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(); InputStream input = new FileInputStream(binaryFile); try { byte[] buffer = new byte[1024]; for (int length = 0; (length = input.read(buffer)) > 0;) { output.write(buffer, 0, length); } output.flush(); // Important! Output cannot be closed. Close of // writer will close output as well. } finally { try { input.close(); } catch (IOException logOrIgnore) {} } writer.append(CRLF).flush(); // CRLF is important! It indicates end // of binary boundary. // End of multipart/form-data. writer.append("--" + boundary + "--").append(CRLF); } finally { if (writer != null) writer.close(); }
如果服务器端是HttpServlet,那么它将会调用doPost()方法处理这个请求,使用HttpServletRequest.getPart()方法访问里边的内容(不是getParameter)。getPart方法在Servlet3.0(Glassfish3,Tomcat7)才被引入,在Servlet3.0之前,最好使用Apache Commons
FileUpload 来处理multipart/form-data请求。
结束语
Apache
HttpComponents HttpClient是很方便的处理http请求。
HttpClient
Tutorial
HttpClient
Examples
解析和提取HTML页面
解析HTML最好使用Jsoup。
What
are the pros/cons of leading HTML parsers in Java
How
to scan and extract a webpage in Java
原文来自:StackOverFlow
相关文章推荐
- android http
- IOCP模型与网络编程
- http杂摘
- Windows单机最大TCP连接数的问题
- 黑马程序员——网络编程
- nagios安装好后输入用户密码后弹出下载页,AddType application /x-httpd-php .php增加那里?
- Google Chrome开发者工具-移动仿真:网络带宽控制
- HTTP通信的具体过程
- http通信和tcp通信
- xmlHttp.status 常见值
- 【Tcpdump】【学习笔记】常用概念UPnP/DLNA/SOAP
- XMLHttpRequest 对象
- 网络编程-----HTTP:HTTP1.1与HTTP1.0的区别(3)
- Microsoft.XMLHttp的用法
- lighttpd 对视频文件压缩文件做防盗链
- 曼彻斯特编码/差分曼彻斯特编码
- 网络编程-----HTTP(2)
- 无法访问.您可能没有权限使用网络资源.局域网无法访问共享,局域网无法访问打印机的一些方法
- 轻松掌握网店经营三步曲
- 网络空间,年轻创业者在这里逐梦