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) ...
随机推荐
- Wcf for wp8 创建wcf服务 连接wp8模拟器并显示来自wcf服务的接口信息 (一)
下载: vs2012 pro for wp8 iis express http://download.microsoft.com/download/B/2/8/B2801FEE-9A60-4AFA-8 ...
- SQL经典短小代码收集
--SQL Server:Select TOP N * From TABLE Order By NewID() --开头到N条记录Select Top N * From 表--N到M条记录(要有主索引 ...
- Android 建立文件夹、生成文件并写入文本文件内容
一.首先添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">& ...
- [hive小技巧]使用limit查询变成抽样,而不是全盘扫描
将set hive.limit.optimize.enable=true 时,limit限制数据时就不会全盘扫,而是根据限制的数量进行抽样. 同时还有两个配置项需要注意: 1.hive.limit.r ...
- node基础 --概念
非阻塞IO: node.js使用了事件轮询 setTimeout是非阻塞的: 对于像http,net等原生模块中IO部分也采用了事件轮询,其本质是: 当node接受到浏览器的http请求时,底层的TC ...
- protected(C# 参考)
protected 关键字是一个成员访问修饰符.受保护成员在它的类中可访问并且可由派生类访问.有关 protected 与其他访问修饰符的比较,请参见可访问性级别. 仅当访问通过派生类类型发生时,基类 ...
- BZOJ3821 : 玄学
对操作建立线段树,每个节点维护一个有序的操作表,表示用$[l,r]$的操作在每段区间上的作用效果. 对于一个线段树节点,合并左右儿子信息只在该区间刚刚被填满时进行,利用归并排序,时间复杂度为$O(n\ ...
- [Unity2D]预制件Prefab
预制件Prefab是一个组件模板,比如在游戏里面要实现开枪的时候会有子弹不停地从枪口飞出来,那么就可以通过Prefab来实现子弹的游戏对象,表示所有的子弹都是从同一个Prefab来构建出来的,也可以理 ...
- oracle系列--第一篇 数据库基础
第一章 数据库基础 1.1 数据管理概述 1.1.1 什么是数据管理 与我们人类相比,计算机的最大优势就是能够高速.精准地运行,其运行的过程就是执行程序代码和操作指令.处理数据的过程.可以说,数据处理 ...
- 模板引擎freemarker的简单使用教程
freemarker十分强大,而且不依赖web容器,个人感觉十分好用. 下面直接进主题,freemarker还有什么特性,请找度娘或谷哥~ 一.freemarker生成word 1.创建模板. 我创建 ...