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的更多相关文章

  1. 解决Fiddler不能监听Java HttpURLConnection请求的方法

    在默认情况下,Fiddler不能监听Java HttpURLConnection请求.究其原因,Java的网络通信协议栈可能浏览器的通信协议栈略有区别,Fiddler监听Http请求的原理是 在应用程 ...

  2. 使用Fiddler监听java HttpURLConnection请求

    使用Fiddler监听java HttpURLConnection请求

  3. Java HttpURLConnection 下载图片 图片全是“加密图片”文字,怎么解决?

    package com.qzf.util; import java.io.FileOutputStream;import java.io.IOException;import java.io.Inpu ...

  4. Java HttpURLConnection模拟请求Rest接口解决中文乱码问题

    转自:http://blog.csdn.net/hwj3747/article/details/53635539 在Java使用HttpURLConnection请求rest接口的时候出现了POST请 ...

  5. java HttpURLConnection 请求实例

    package app.works; import org.json.JSONObject; import java.io.BufferedReader; import java.io.InputSt ...

  6. java HttpURLConnection 登录网站 完整代码

    import java.io.*; import java.util.*; import java.net.*; public class WebTest { public static void m ...

  7. JAVA httpURLConnection curl

    // 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestHttpCurl.java package com.test; import ...

  8. Java HttpURLConnection 抓取网页内容 解析gzip格式输入流数据并转换为String格式字符串

    最近GFW为了刷存在感,搞得大家是头晕眼花,修改hosts 几乎成了每日必备工作. 索性写了一个小程序,给办公室的同事们分享,其中有个内容 就是抓取网络上的hosts,废了一些周折. 我是在一个博客上 ...

  9. Java HttpURLConnection发送post请求示例

    public static Map<String, Object> invokeCapp(String urlStr, Map<String, Object> params) ...

随机推荐

  1. VMware 虚拟机网络 组网问题

    1.VMware虚拟机组网概述 整个结构: 需要确定的内容: 1) 虚拟机连接到哪个VMnet(交换机)? 2) VMnet(交换机)的组网模式? 首先,讲一下VMware的界面内容 安装好VMwar ...

  2. Hark的数据结构与算法练习之简单选择排序

    /* * 简单选择排序 */ public class SimpleSort { public static void main(String[] args) { int[] arrayData = ...

  3. Xamarin Android设置界面提示类型错误

    Xamarin Android设置界面提示类型错误 错误信息:Integer types not allow (at ‘padding’ with value ’10’)Android界面属性的长度和 ...

  4. Buy the Ticket

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission( ...

  5. 简单几何(判断矩形的位置) UVALive 7070 The E-pang Palace(14广州B)

    题目传送门 题意:给了一些点,问组成两个不相交的矩形的面积和最大 分析:暴力枚举,先找出可以组成矩形的两点并保存起来(vis数组很好),然后写个函数判断四个点是否在另一个矩形内部.当时没有保存矩形,用 ...

  6. Unity3D中Update和Lateupdate的区别

    Unity中Update和Lateupdate的区别.Lateupdate和Update每一祯都被执行,但是执行顺序不一样,先执行Updatee然后执行lateUpdate. 如果你有两个脚本JS1. ...

  7. BZOJ3153 : Sone1

    Top Tree模板题,写起来真不是一般的蛋疼,调了两天.常数写渣了TAT Top Tree就是在LCT的基础上加以改动,将虚边也用splay维护, 对于A向儿子所连出去的虚边,用Splay维护↓ 为 ...

  8. Channel 笔记本项目 (门户客户端(介绍1) 和 wp7客户端)

  9. mysql 截取指定的两个字符串之间的内容(locate,substring)

    如需转帖,请写明出处 http://blog.csdn.net/slimboy123/archive/2009/07/30/4394782.aspx 今天我同事在用mysql的时候,需要对一个字符串中 ...

  10. 对于PKI(公钥基础结构)及证书服务的通俗理解

    对于PKI及证书服务的这些概念,相信初学者会有许多迷惑的地方,那是因为其中的某些关键概念没有理解清楚,我力争以通俗易懂的方式给初学者一些启示,也给以后自己忘了的时候一个参考:) ! 参考资料:http ...