Java - HttpURLConnection
JDK中的URLConnection参数详解
1:> URL请求的类别:
分为二类,GET与POST请求。二者的区别在于:
a:) get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给servlet,
b:) post与get的不同之处在于post的参数不是放在URL字串里面,而是放在http请求的正文内。
2:> URLConnection的对象问题:
// URLConnection的对象,如下代码示例: URL url = new URL("http://localhost:8080/TestHttpURLConnectionPro/index.jsp"); URLConnection rulConnection = url.openConnection();
得到的是URLConnection对象, 此处的urlConnection对象实际上是根据URL的请求协议(此处是http)生成的URLConnection类的子类HttpURLConnection,故此处最好将其转化 为HttpURLConnection类型的对象,以便用到 HttpURLConnection更多的API.如下:
HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
HttpURLConnection:
任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。
这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。
3:> HttpURLConnection对象参数问题 请求header配置
httpUrlConnection.setDoOutput(true);// 如果后面需要使用httpUrlConnection.getOutputStream().write() 默认值是false httpUrlConnection.setDoInput(true); // 如果后面需要使用httpUrlConnection.getInputStream().read(); 默认值是true
get请求用不到conn.getOutputStream(),因为参数直接追加在地址后面,它没有请求正文body, 不需要往服务等写数据,因此默认是false。
post请求(比如:文件上传)需要往服务区传输大量的数据,这些数据是放在http的body里面的,因此需要在建立连接以后,往服务端写数据。
因为总是使用conn.getInputStream()获取服务端的响应,因此默认值是true。
简单一句话:get请求的话默认就行了; post请求需要setDoOutput(true),这个默认是false的。
通过httpUrlConnection.setRequestProperty("header_name", "value"); Sets the value of the specified request header field.
Mainly setRequestProperty is used to set below things as per the requirement:
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive"); // 设定传送的内容类型 httpUrlConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary); //or httpUrlConnection.setRequestProperty("Content-Type", "text/plain; charset=utf-8");
Sometimes it become necessary that you have to specify Content-type for the connection.
其他常见的请求header设置
httpUrlConnection.setRequestMethod("POST"); //设定请求的方法为"POST",默认是GET httpUrlConnection.setUseCaches(false); // Post 请求不能使用缓存 httpUrlConnection.setRequestProperty("Cookie", cookieString); //cookieStringformat:xxx=value;xxx2=value2;xxx3=value3; //HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时: conn.setConnectTimeout(1000 * 60 * 1); //设置连接主机超时间(单位:毫秒) conn.setReadTimeout(1000 * 60 * 5); //设置从主机读取数据超时间(单位:毫秒)
connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前, 就必须把所有的配置准备好。
httpUrlConnection.connect();
4:> HttpURLConnection请求body正文配置
在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的:
String body = "body_value"; OutputStream out = httpUrlConnection.getOutputStream(); // 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法 所以在开发中不调用上述的connect()也可以)。 out.write(body.getBytes()); // 向输出量写入request请求正文的字节数组 out.flush(); // 刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream) no need this outputStream??? out.close(); //关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区中。 在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器
实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。
http请求实际上由两部分组成,
一个是http头,所有关于此次http请求的配置都在http头里面定义 -> step 3 配置
一个是正文content -> step 4配置
至此,http请求的东西已经全部准备就绪。
在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的Response信息。
由于http请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数, 之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。
5:> 获取响应数据
Response resp = new Response(); //创建Response 响应对象 resp.setStatusCode(con.getResponseCode()); // 获取response的响应代码 resp.setResponseHeaders(con.getHeaderFields()); // 获取response的Headers 信息
调用HttpURLConnection连接对象的getInputStream()函数, 将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。
InputStream inputStream = httpConn.getInputStream(); // <===注意,实际发送请求的代码段就在这里 //读取response 的正文内容 ByteArrayOutputStream container = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int read; while ((read = inputStream.read(buf, 0, 1024)) > 0) { container.write(buf, 0, read); } resp.setResponseData(container.toByteArray()); return resp;
6:> 如果返回的response 正文内容是json 转为java bean对象
Bean[] array = new Gson().fromJson(response.toString(), Bean[].class); List<Bean> beanList = Arrays.asList(array);
总结:
a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。 无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,
对connection对象的一切配置(那一堆set函数,配置request header) 都必须要在connect()函数执行之前完成。
而对outputStream的写操作,又必须要在inputStream的读操作之前。
这些顺序实际上是由http请求的格式决定的。
如果inputStream读操作在outputStream的写操作之前,会抛出异常 java.net.ProtocolException: Cannot write output after reading input.......
c:) http请求实际上由两部分组成,
一个是http头,所有关于此次http请求的配置都在http头里面定义,
一个是正文content。
connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前, 就必须把所有的配置准备好。
d:) 在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的:
OutputStream out = httpUrlConnection.getOutputStream();
out.write(body.getBytes()); //
out.flush();
out.close();
e:) 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义,既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据.
因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、 重新发送数据(至于是否不用重新这些操作需要再研究)
out.write(new String(""));
httpUrlConnection.getInputStream();
6: Servlet端的开发注意点:
a:) 对于客户端发送的POST类型的HTTP请求,Servlet必须实现doPost方法,而不能用doGet方法。
b:) 用HttpServletRequest的getInputStream()方法取得InputStream的对象,比如:
InputStream inStream = httpRequest.getInputStream();
现在调用inStream.available()(该方法用于“返回此输入流下一个方法调用可以不受阻塞地
从此输入流读取(或跳过)的估计字节数”)时,永远都反回0。试图使用此方法的返回值分配缓冲区,
以保存此流所有数据的做法是不正确的。那么,现在的解决办法是
Servlet这一端用如下实现:
InputStream inStream = httpRequest.getInputStream();
ObjectInputStream objInStream = new ObjectInputStream(inStream);
Object obj = objInStream.readObject();
// 做后续的处理
// 。。。。。。
// 。。。 。。。
而客户端,无论是否发送实际数据都要写入一个对象(那怕这个对象不用),如:
ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm);
objOutputStrm.writeObject(new String("")); // 这里发送一个空数据
// 甚至可以发一个null对象,服务端取到后再做判断处理。
objOutputStrm.writeObject(null);
objOutputStrm.flush();
objOutputStrm.close();
注意:上述在创建对象输出流ObjectOutputStream时,如果将从HttpServletRequest取得的输入流
(即:new ObjectOutputStream(outStrm)中的outStrm)包装在BufferedOutputStream流里面,
则必须有objOutputStrm.flush();这一句,以便将流信息刷入缓冲输出流.如下:
ObjectOutputStream objOutputStrm = new ObjectOutputStream(new BufferedOutputStream(outStrm));
objOutputStrm.writeObject(null);
objOutputStrm.flush(); // <======此处必须要有.
objOutputStrm.close();
JDK 1.5以前的版本可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);
在1.5以后,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)
虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStream或OutputStream的close()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket。
设置请求头或响应头
HTTP请求允许一个key带多个用逗号分开的values,但是HttpURLConnection只提供了单个操作的方法:
setRequestProperty(key,value)
addRequestProperty(key,value)
setRequestProperty和addRequestProperty的区别就是,setRequestProperty会覆盖已经存在的key的所有values,有清零重新赋值的作用。而addRequestProperty则是在原来key的基础上继续添加其他value。
Java - HttpURLConnection的更多相关文章
- 解决Fiddler不能监听Java HttpURLConnection请求的方法
在默认情况下,Fiddler不能监听Java HttpURLConnection请求.究其原因,Java的网络通信协议栈可能浏览器的通信协议栈略有区别,Fiddler监听Http请求的原理是 在应用程 ...
- 使用Fiddler监听java HttpURLConnection请求
使用Fiddler监听java HttpURLConnection请求
- Java HttpURLConnection 下载图片 图片全是“加密图片”文字,怎么解决?
package com.qzf.util; import java.io.FileOutputStream;import java.io.IOException;import java.io.Inpu ...
- Java HttpURLConnection模拟请求Rest接口解决中文乱码问题
转自:http://blog.csdn.net/hwj3747/article/details/53635539 在Java使用HttpURLConnection请求rest接口的时候出现了POST请 ...
- java HttpURLConnection 请求实例
package app.works; import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputSt ...
- java HttpURLConnection 登录网站 完整代码
import java.io.*; import java.util.*; import java.net.*; public class WebTest { public static void m ...
- JAVA httpURLConnection curl
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestHttpCurl.java package com.test; import ...
- Java HttpURLConnection 抓取网页内容 解析gzip格式输入流数据并转换为String格式字符串
最近GFW为了刷存在感,搞得大家是头晕眼花,修改hosts 几乎成了每日必备工作. 索性写了一个小程序,给办公室的同事们分享,其中有个内容 就是抓取网络上的hosts,废了一些周折. 我是在一个博客上 ...
- Java HttpURLConnection发送post请求示例
public static Map<String, Object> invokeCapp(String urlStr, Map<String, Object> params) ...
随机推荐
- VMware 虚拟机网络 组网问题
1.VMware虚拟机组网概述 整个结构: 需要确定的内容: 1) 虚拟机连接到哪个VMnet(交换机)? 2) VMnet(交换机)的组网模式? 首先,讲一下VMware的界面内容 安装好VMwar ...
- Hark的数据结构与算法练习之简单选择排序
/* * 简单选择排序 */ public class SimpleSort { public static void main(String[] args) { int[] arrayData = ...
- Xamarin Android设置界面提示类型错误
Xamarin Android设置界面提示类型错误 错误信息:Integer types not allow (at ‘padding’ with value ’10’)Android界面属性的长度和 ...
- Buy the Ticket
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...
- 简单几何(判断矩形的位置) UVALive 7070 The E-pang Palace(14广州B)
题目传送门 题意:给了一些点,问组成两个不相交的矩形的面积和最大 分析:暴力枚举,先找出可以组成矩形的两点并保存起来(vis数组很好),然后写个函数判断四个点是否在另一个矩形内部.当时没有保存矩形,用 ...
- Unity3D中Update和Lateupdate的区别
Unity中Update和Lateupdate的区别.Lateupdate和Update每一祯都被执行,但是执行顺序不一样,先执行Updatee然后执行lateUpdate. 如果你有两个脚本JS1. ...
- BZOJ3153 : Sone1
Top Tree模板题,写起来真不是一般的蛋疼,调了两天.常数写渣了TAT Top Tree就是在LCT的基础上加以改动,将虚边也用splay维护, 对于A向儿子所连出去的虚边,用Splay维护↓ 为 ...
- Channel 笔记本项目 (门户客户端(介绍1) 和 wp7客户端)
- mysql 截取指定的两个字符串之间的内容(locate,substring)
如需转帖,请写明出处 http://blog.csdn.net/slimboy123/archive/2009/07/30/4394782.aspx 今天我同事在用mysql的时候,需要对一个字符串中 ...
- 对于PKI(公钥基础结构)及证书服务的通俗理解
对于PKI及证书服务的这些概念,相信初学者会有许多迷惑的地方,那是因为其中的某些关键概念没有理解清楚,我力争以通俗易懂的方式给初学者一些启示,也给以后自己忘了的时候一个参考:) ! 参考资料:http ...