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. JAVA 正则表达式、汉字正则、 java正则代码

    转自于:http://blog.csdn.net/q326527970/article/details/7513974 (一)字母.数字.下划线.汉字正则表达式 1. 只有字母.数字和下划线且不能以下 ...

  2. QUnit使用笔记-5简化编写

    在测试中,如果用到了大量相同的方法返回判断结果,可以将他们简化; 使用push(): push( result/*boolean,result of assert*/, actual, /*objec ...

  3. QUnit使用笔记-2同步与异步处理方式

    同步: 有时候如果我们想判断方法执行的次数,可以通过间接设置expect(n);//可以将expect的参数放到test的第二参数来简化: QUnit.test("expect test&q ...

  4. Linux下设置memcached访问IP

    在虚拟机上装了memcached,本地访问可以,但从其它机器连这台机器的memcached应用总是报连接失败.防火墙的端口都是打开的.Google了才知道原来需要修改memcached的配置文件,将默 ...

  5. 拼图游戏 v1.1

    我一直对拼图游戏比较有兴趣,市面上卖的所谓“1000块拼图”也玩过不少,不过玩那个太占地方,后来也不再买了,同时也就萌生了在电脑上玩拼图的想法. 现在虽然有很多拼图游戏,但能大多数只能支持几十或几百块 ...

  6. DelPhi连接数据库方式

    一.SQL Server 2000 的连接数据库 1.无密码连接SQLL:='Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;In ...

  7. Photoshop: 机关单位公章

    机关单位公章的大小与机构的级别有关,级别越高的公章越大,一般直径在3.8-4.2cm,很少有用4.5cm或3.4cm的.但企业的公章一般都很大. 首先点击文件新建,新建一个500×500像素(像素大小 ...

  8. JAVA图片处理--缩放,切割,类型转换

    import java.io.*; import java.awt.*; import java.awt.image.*; import java.awt.Graphics; import java. ...

  9. imread() not working in OpenCV 2.4.11 Debug mode

    The OpenCV function imread() not working in OpenCV 2.4.11 Debug mode of VS2010 under Win32, the way ...

  10. stringstream 使用方法

    C++中的stringstream是专门用来处理字符串流的,可以按顺序将string或int都拼接起来,而不用把int转换为string格式,使用方法如下: #include <string&g ...