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. PHP单引号和双引号的区别

    单引号和双引号的区别 .双引号 里的东西 输入的时候能判断是否 包含 变量,如果包含 变量 就一起输出 .单引号里的就不一样,不判断是否有变量,就全部当成 字符串 输出 .单引号解析的时间比双引号快 ...

  2. cocos2dx游戏开发——微信打飞机学习笔记(六)——PlayerLayer的搭建

    一.创建文件~ PlayerLayer.h PlayerLayer.cpp 一般类名都会和文件名有关系的~(在这里当然是一样) 二.How to do? 1.首先就是放一个飞机~ CC_SYNTHES ...

  3. ViewPager左右滑动

    布局: <android.support.v4.view.ViewPager android:id="@+id/viewpager_main" android:layout_ ...

  4. Android DrawerLayout 高仿QQ5.2双向侧滑菜单

    1.概述 之前写了一个Android 高仿 QQ5.0 侧滑菜单效果 自定义控件来袭 ,恰逢QQ5.2又加了一个右侧菜单,刚好看了下DrawerLayout,一方面官方的东西,我都比较感兴趣:另一方面 ...

  5. html 绘图渐变和图片填充

    包括线性渐变和径向渐变 <!DOCTYPE html> <html> <head lang="en"> <meta charset=&qu ...

  6. Xamarin开发Anroid应用介绍

    第1章  Xamarin开发Anroid应用介绍 如今智能手机已经盛行了好几年,而针对这些智能手机的软件开发也变得异常火热.但是在Android平台下只能使用Java开发,iOS平台下也只能使用Obj ...

  7. 哈希表--HashSet<T>

    .Net3.5之后出现了HashSet<T>,硬翻译过来就是“哈希集合”,跟“哈希”两字挂钩说明这种集合的内部实现用到了哈希算法,用Reflector工具就可以发现,HashSet< ...

  8. stack UVA 442 Matrix Chain Multiplication

    题目传送门 题意:给出每个矩阵的行列,计算矩阵的表达式,如果错误输出error,否则输出答案 分析:表达式求值,stack 容器的应用:矩阵的表达式求值A 矩阵是a * b,B 矩阵是b * c,则A ...

  9. How Many Trees?[HDU1130]

    How Many Trees? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  10. jQuery Select操作大集合

    jQuery获取Select选择的Text和Value: 语法解释:  $("#select_id").change(function(){//code...});    //为S ...