本文将介绍HttpURLConnection 以及其父类URLConnection中的常用方法以及成员变量,并且会通过例子来看看这些方法的用处。
一、HttpURLConnection.java1. HttpURLConnection.java常用的方法:
(1) void setRequestMethod(String method) //设置请求方法
/**
* The HTTP method (GET,POST,PUT,etc.).
*/
protected String method = "GET"; //在HttpURLConnection中将会默认请求方法为"GET",开发者可通过下面方法进行重新设置
public void setRequestMethod(String method) throws ProtocolException {
if (connected) { //如果当前已经连接,将抛出protocolException 提示已连接
throw new ProtocolException("Can't reset method: already connected");
}
// This restriction will prevent people from using this class to
// experiment w/ new HTTP methods using java. But it should
// be placed for security - the request String could be
// arbitrarily long.
for (int i = 0; i < methods.length; i++) {
if (methods[i].equals(method)) {
if (method.equals("TRACE")) { //如果是trace,则会判断权限,因为这将暴露出一些私人信息
SecurityManager s = System.getSecurityManager();
if (s != null) {
s.checkPermission(new NetPermission("allowHttpTrace"));
}
}
this.method = method; //将值赋给method
return;
}
}
throw new ProtocolException("Invalid HTTP method: " + method);
}
(2)String getRequestMethod() //获取请求方法
直接return method;
(3)int getResponseCode() //获得响应状态码
public int getResponseCode() throws IOException {
/*
* We're got the response code already
*/
if (responseCode != -1) { //responseCode不为-1时,说明已经存在
return responseCode;
}
/*
* Ensure that we have connected to the server. Record
* exception as we need to re-throw it if there isn't
* a status line.
*/
Exception exc = null;
try {
getInputStream(); //此时还没有状态行,所以通过getInputStream() 进行connect
} catch (Exception e) {
exc = e;
}
/*
* If we can't a status-line then re-throw any exception
* that getInputStream threw.
*/
String statusLine = getHeaderField(0); //一般在连接失败时出现
if (statusLine == null) {
if (exc != null) {
if (exc instanceof RuntimeException)
throw (RuntimeException)exc;
else
throw (IOException)exc;
}
return -1;
}
/*
* Examine the status-line - should be formatted as per
* section 6.1 of RFC 2616 :-
*
* Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase //上篇文章讲过状态行的组成 HTTP版本号, 响应状态码 , 状态码文本描述
*
* If status line can't be parsed return -1.
*/
if (statusLine.startsWith("HTTP/1.")) { //比如 HTTP/1.1 200 OK
int codePos = statusLine.indexOf(' '); //状态行以空格隔开 8
if (codePos > 0) {
int phrasePos = statusLine.indexOf(' ', codePos+1); // 12
if (phrasePos > 0 && phrasePos < statusLine.length()) {
responseMessage = statusLine.substring(phrasePos+1); //此时获得状态码文本描述 OK 13位置往后就是OK了
}
// deviation from RFC 2616 - don't reject status line
// if SP Reason-Phrase is not included.
if (phrasePos < 0)
phrasePos = statusLine.length();
try {
responseCode = Integer.parseInt
(statusLine.substring(codePos+1, phrasePos)); //获得状态码 9~12 为200
return responseCode;
} catch (NumberFormatException e) { }
}
}
return -1;
}
(3)String getResponseMessage() //获取响应状态码的描述
直接return responseMessage; 在上面方法中已经获得
(4)long getHeaderFieldDate(String name, long Default) //响应日期
public long getHeaderFieldDate(String name, long Default) {
String dateString = getHeaderField(name); //父类中的方法,获得响应头中的键值对
try {
if (dateString.indexOf("GMT") == -1) { //一般为Date Wed, 12 Jul 2017 10:59:31 GMT
dateString = dateString+" GMT";
}
return Date.parse(dateString);
} catch (Exception e) {
}
return Default;
}
(5)void disconnect() //取消连接
抽象方法,指在一段时间内不太可能进行连接
(6)boolean usingProxy() //连接是否通过代理
抽象方法
(7)Permission getPermission() //获得权限
public Permission getPermission() throws IOException {
int port = url.getPort();
port = port < 0 ? 80 : port;
String host = url.getHost() + ":" + port;
Permission permission = new SocketPermission(host, "connect"); //建立此HttpURLConnection所需要的权限
return permission;
}
(8)InputStream getErrorStream() //获得错误信息
连接失败,但服务器还是返回数据,此时走错误流
2. HttpURLConnection.java常用的成员变量或静态常量:
下面主要是与状态码相关的静态常量
/**
* HTTP Status-Code 200: OK.
*/
public static final int HTTP_OK = 200;
/**
* HTTP Status-Code 201: Created.
*/
public static final int HTTP_CREATED = 201;
/**
* HTTP Status-Code 202: Accepted.
*/
public static final int HTTP_ACCEPTED = 202;
/**
* HTTP Status-Code 203: Non-Authoritative Information.
*/
public static final int HTTP_NOT_AUTHORITATIVE = 203;
/**
* HTTP Status-Code 204: No Content.
*/
public static final int HTTP_NO_CONTENT = 204;
/**
* HTTP Status-Code 205: Reset Content.
*/
public static final int HTTP_RESET = 205;
/**
* HTTP Status-Code 206: Partial Content.
*/
public static final int HTTP_PARTIAL = 206;
/* 3XX: relocation/redirect */
/**
* HTTP Status-Code 300: Multiple Choices.
*/
public static final int HTTP_MULT_CHOICE = 300;
/**
* HTTP Status-Code 301: Moved Permanently.
*/
public static final int HTTP_MOVED_PERM = 301;
/**
* HTTP Status-Code 302: Temporary Redirect.
*/
public static final int HTTP_MOVED_TEMP = 302;
/**
* HTTP Status-Code 303: See Other.
*/
public static final int HTTP_SEE_OTHER = 303;
/**
* HTTP Status-Code 304: Not Modified.
*/
public static final int HTTP_NOT_MODIFIED = 304;
/**
* HTTP Status-Code 305: Use Proxy.
*/
public static final int HTTP_USE_PROXY = 305;
/* 4XX: client error */
/**
* HTTP Status-Code 400: Bad Request.
*/
public static final int HTTP_BAD_REQUEST = 400;
/**
* HTTP Status-Code 401: Unauthorized.
*/
public static final int HTTP_UNAUTHORIZED = 401;
/**
* HTTP Status-Code 402: Payment Required.
*/
public static final int HTTP_PAYMENT_REQUIRED = 402;
/**
* HTTP Status-Code 403: Forbidden.
*/
public static final int HTTP_FORBIDDEN = 403;
/**
* HTTP Status-Code 404: Not Found.
*/
public static final int HTTP_NOT_FOUND = 404;
/**
* HTTP Status-Code 405: Method Not Allowed.
*/
public static final int HTTP_BAD_METHOD = 405;
/**
* HTTP Status-Code 406: Not Acceptable.
*/
public static final int HTTP_NOT_ACCEPTABLE = 406;
/**
* HTTP Status-Code 407: Proxy Authentication Required.
*/
public static final int HTTP_PROXY_AUTH = 407;
/**
* HTTP Status-Code 408: Request Time-Out.
*/
public static final int HTTP_CLIENT_TIMEOUT = 408;
/**
* HTTP Status-Code 409: Conflict.
*/
public static final int HTTP_CONFLICT = 409;
/**
* HTTP Status-Code 410: Gone.
*/
public static final int HTTP_GONE = 410;
/**
* HTTP Status-Code 411: Length Required.
*/
public static final int HTTP_LENGTH_REQUIRED = 411;
/**
* HTTP Status-Code 412: Precondition Failed.
*/
public static final int HTTP_PRECON_FAILED = 412;
/**
* HTTP Status-Code 413: Request Entity Too Large.
*/
public static final int HTTP_ENTITY_TOO_LARGE = 413;
/**
* HTTP Status-Code 414: Request-URI Too Large.
*/
public static final int HTTP_REQ_TOO_LONG = 414;
/**
* HTTP Status-Code 415: Unsupported Media Type.
*/
public static final int HTTP_UNSUPPORTED_TYPE = 415;
/* 5XX: server error */
/**
* HTTP Status-Code 500: Internal Server Error.
* @deprecated it is misplaced and shouldn't have existed.
*/
@Deprecated
public static final int HTTP_SERVER_ERROR = 500;
/**
* HTTP Status-Code 500: Internal Server Error.
*/
public static final int HTTP_INTERNAL_ERROR = 500;
/**
* HTTP Status-Code 501: Not Implemented.
*/
public static final int HTTP_NOT_IMPLEMENTED = 501;
/**
* HTTP Status-Code 502: Bad Gateway.
*/
public static final int HTTP_BAD_GATEWAY = 502;
/**
* HTTP Status-Code 503: Service Unavailable.
*/
public static final int HTTP_UNAVAILABLE = 503;
/**
* HTTP Status-Code 504: Gateway Timeout.
*/
public static final int HTTP_GATEWAY_TIMEOUT = 504;
/**
* HTTP Status-Code 505: HTTP Version Not Supported.
*/
public static final int HTTP_VERSION = 505;
二、父类URLConnection.java
(1)void setConnectTimeout(int timeout) //设置连接超时时间
将值赋给 connectTimeout = timeout;
(2)int getConnectTimeout() //返回连接超时时间
直接return connectTimeout ;
(3)void setReadTimeout(int timeout) //设置读超时时间
将值赋给readTimeout = timeout;
(4)int getReadTimeout() //返回读超时时间
直接return readTimeout ;
(5)URL getURL() //返回URL
(6)int getContentLength() //返回content-length 头字段的值
在HTTP协议中,Content-Length用于描述HTTP消息实体的传输长度the transfer-length of the message-body。在HTTP协议中,消息实体长度和消息实体的传输长度是有区别,比如说gzip压缩下,消息实体长度是压缩前的长度,消息实体的传输长度是gzip压缩后的长度。
(7)String getContentType() //返回content-type头字段的值
服务器发送内容的类型和编码类型
(8)String getContentEncoding() //返回content-encoding头字段的值
服务器发送的压缩编码方式
(9)long getExpiration() //返回 expires 头字段的值
用来控制网页缓存的失效日期
(10)long getDate() //返回date头字段的值
获得HTTP响应消息头中的Date字段的值,返回的是服务器响应的时间
(11)long getLastModified() //返回last-modified头字段的值
HTTP响应消息头有一个Last-Modified字段,这个字段表示服务器内容最新修改时间。如果请求消息头中包含If-Modificed-Since字段,并且该字段的时间比Last-Modified字段的时间早。或是请求消息头中没有If-Modificed-Since字段。service方法就会调用doGet方法来重新获得服务端内容。但这有一个前提,就是getLastModified方法必须返回一个正数。但在默认情况下,getLastModified方法返回-1.因此,service方法调用用doGet方法的规则如下: 当getLastModified返回-1时,service方法总会调用doGet方法。
6~11这几个方法,是通过字段key content-length content-type content-encoding expires date last-modified 在方法getHeaderField中获得值
public String getHeaderField(String name) {
return null; //源码中看到的是null, 实际应该响应消息头的一个解析。
}
(12)InputStream getInputStream() //获得输入流
从此打开的连接读入的输入流。 内部包含connect的操作
抛出:
IOException - 如果在创建输入流时发生 I/O 错误。
UnknownServiceException - 如果协议不支持输入。
(13)OutputStream getOutputStream() //获得输出流
写入到此连接的输出流。
抛出:
IOException - 如果在创建输出流时发生 I/O 错误。
UnknownServiceException - 如果协议不支持输出。
三、常见的请求头与响应头(后面括号内有解释错误的可以留言更改- -。)
请求头:
Accept: text/html,image/*(浏览器可以接收的类型)
Accept-Charset: ISO-8859-1(浏览器可以接收的编码类型)
Accept-Encoding: gzip,compress(浏览器可以接收压缩编码类型)
Accept-Language: en-us,zh-cn(浏览器可以接收的语言和国家类型)
Host: www.it315.org:80(浏览器请求的主机和端口)
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(某个页面缓存时间)
Referer: http://www.it315.org/index.jsp(请求来自于哪个页面)
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)(浏览器相关信息)
Cookie:(浏览器暂存服务器发送的信息)
Connection: close(1.0)/Keep-Alive(1.1)(HTTP请求的版本的特点)
Date: Tue, 11 Jul 2000 18:23:51 GMT(请求网站的时间)
响应头:
Location: http://www.it315.org/index.jsp(控制浏览器显示哪个页面)
Server:apache tomcat(服务器的类型)
Content-Encoding: gzip(服务器发送的压缩编码方式)
Content-Length: 80(服务器发送显示的字节码长度)
Content-Language: zh-cn(服务器发送内容的语言和国家名)
Content-Type: image/jpeg; charset=UTF-8(服务器发送内容的类型和编码类型)
Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT(服务器最后一次修改的时间)
Refresh: 1;url=http://www.it315.org(控制浏览器1秒钟后转发URL所指向的页面)
Content-Disposition: attachment; filename=aaa.jpg(服务器控制浏览器发下载方式打开文件)
Transfer-Encoding: chunked(服务器分块传递数据到客户端)
Set-Cookie:SS=Q0=5Lb_nQ; path=/search(服务器发送Cookie相关的信息)
Expires: -1(服务器控制浏览器不要缓存网页,默认是缓存)
Cache-Control: no-cache(服务器控制浏览器不要缓存网页)
Pragma: no-cache(服务器控制浏览器不要缓存网页)
Connection: close/Keep-Alive(HTTP请求的版本的特点)
Date: Tue, 11 Jul 2000 18:23:51 GMT(响应网站的时间)
四、简单举例一下部分方法
url = new URL(strings[0]);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setReadTimeout(5000);
httpURLConnection.setDoOutput(false);
httpURLConnection.setDoInput(false);
httpURLConnection.connect();
int responseCode = httpURLConnection.getResponseCode();
int readTimeout = httpURLConnection.getReadTimeout();
String responseMessage = httpURLConnection.getResponseMessage();
long date = httpURLConnection.getDate();
String contentEncoding = httpURLConnection.getContentEncoding();
arrayList = new ArrayList<String>();
arrayList.add("responseCode = " + responseCode);
arrayList.add("readTimeout = " + readTimeout);
arrayList.add("responseMessage = " + responseMessage);
arrayList.add("date = " + date);
arrayList.add("contentEncoding = " + contentEncoding);
// 01-05 21:48:26.248 12592 12592 D result : responseCode = 200
// 01-05 21:48:26.248 12592 12592 D result : readTimeout = 5000
// 01-05 21:48:26.248 12592 12592 D result : responseMessage = OK
// 01-05 21:48:26.249 12592 12592 D result : date = 1500376608000
// 01-05 21:48:26.249 12592 12592 D result : contentEncoding = null
if (code == 200) {
InputStream is = huc.getInputStream();
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = is.read(buffer)) != -1) {
output.write(buffer, 0, len);
}
is.close();
output.close();
text = new String(output.toByteArray(), "utf-8"); //此时可获得百度首页源码信息
}
01-05 21:56:19.913 13180 13199 D result : <html><!--STATUS OK--><head><script>var actionSta = 1;if (actionSta === 1) {var startTime = Date.now();} else {var endTime = Date.now();}if (actionSta === 1 || (endTime && (endTime - startTime) > 3000)) {actionSta = actionSta == 1 ? 'start' : 'end';new Image().src = '//hpd.baidu.com/v.gif?tid=365&funcSta=whiteScreenEx&sourceSta=wiseindex&actionSta='+ actionSta + '&logid=1482073863&ssid=0'+ '&ct=1&cst=9&logFrom=mid_news&logInfo=stability';}</script><meta name="referrer" content="always" /><meta charset='utf-8' /><meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/><meta http-equiv="x-dns-prefetch-control" content="on"><link rel="dns-prefetch" href="//m.baidu.com"/><link rel="shortcut icon" href="https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/favicon.ico" type="image/x-icon"><link rel="apple-touch-icon-precomposed" href="https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/screen_icon.png"/><meta name="format-detection" content="telephone=no"/><noscript><style type="text/css">#page{display:none;}</style><meta http-equiv="refresh" content="0; URL=http://m.baidu.com/index/index.php?from=844b&vit=fps&pu=sz%401321_480&t_noscript=jump" /></noscript><title>百度一下</title><script type="text/javascript">window.οnerrοr=function(m,b,n,l,k){var f="//hpd.baidu.com/v.gif";var c={tid:"259",ct:"1",cst:"9",logFrom:"mid_news",logInfo:"jsException",r:"l"+(Date.now()),logExtra:{rta:"wise"}};var d={};d.message=m||"";d.url=b||"";d.line=n||"";c.logExtra["excep"]=d;try{c.logExtra=JSON.stringify(c.logExtra)}catch(j){}var g="";for(var h in c){if(c.hasOwnProperty(h)){g+="&"+h+"="+encodeURIComponent(c[h])}}var a=f+"?"+g.slice(1);new Image().src=a};;</script><style type="text/css" id='spa-base-style'>#search-card {display: none;}</style><style type="text/css">@font-face {font-family: 'icons';src: url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_9c0cdb21.eot);src: url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_9c0cdb21.eot#iefix) format('embedded-opentype'),url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_11a872b9.woff) format('woff'),url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_0b0a971d.ttf) format('truetype'),url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_b8b3267e.svg#iconfont) format('svg');font-weight: normal;font-style: normal;}i.ns-focus,i.ns-news,i.ns-novel,i.ns-video,i.ns-life,i.ns-map,i.ns-tieba,i.ns-app,i.ns-image,i.ns-website,i.ns-extend,i.ns-music,i.ns-listen {background: url(https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/ns_diff_color_v2_3d39b4dd.png) no-repeat;background-size: 22px auto;}</style><style type="text/css" class="spa-index-style" data-lsid="plus_css_head">body,h1,h2,h3,p,div,ol,ul,input,button{margin:0;padding:0}body{font-family:Arial, Helvetica, sans-serif;text-align:center;-webkit-text-size-adjust:none;background:#f1f1f1;max-width:100%;overflow-x:hidden}ol,ul{list-style:none}a{text-decoration:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}input,button,textarea{border:0;border-radius:0;background:transparent;-webkit-appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}button{outline:none}#index-card [class^="icon-"],#index-card [class*=" icon-"],#__SF___mine [class^="icon-"],#__SF___mine [class*=" icon-"],#index-view [class^="icon-"],#index-view [class*=" icon-"]{font-family:icons;font-style:normal;-webkit-font-smoothing:antialiased;-webkit-text-stroke-width:.2px}#__SF___mine .normal-title > i{position:absolute;top:11px;left:-2px;display:none}#__SF___mine .icon-add,#index-view .icon-add{//font-size:24px;color:#B6B7BA;display:inherit;margin:auto}#__SF___mine .icon-add:before{content:'\e888';font:16px/16px icons;color:#999}#__SF___mine .plus-empty .icon-add-empty:before{content:'';position:absolute;top:50%;left:50%;height:1px;width:16px;margin-top:-1px;margin-left:-8px;border-ra