HttpUrlConnection get和post简单实现(疑惑解决)
近期研究微信的公众平台开发。须要和微信的server进行数据读取,简单研究了下jdk自带的HttpUrlConnection类(URLConnection的子类),简单实现了一下微信的access_token获取。
获取微信access_token的地址:微信地址
该地址是get方法请求就可以。先贴代码,doGet:
private final String ACCESS_TOKEN_WEIXIN = "https://api.weixin.qq.com/cgi-bin/token";
public String doGet(String grantType, String appId, String secret){
String url = ACCESS_TOKEN_WEIXIN+"?grant_type="+grantType+
"&appid="+appId+"&secret="+secret;
HttpURLConnection conn = null;
InputStream is = null;
InputStreamReader reader = null;
BufferedReader br = null;
String str = "";
try {
URL weiUrl = new URL(url);
conn = (HttpURLConnection)weiUrl.openConnection();
conn.setRequestProperty("connection", "Keep-Alive");
conn.connect();
is = conn.getInputStream();
reader = new InputStreamReader(is, "UTF-8");
br = new BufferedReader(reader);
String readLine = "";
while((readLine=br.readLine())!=null){
str+=readLine+"\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
if(br!=null){
br.close();
}
if(conn!=null){
conn.disconnect();
}
}catch(Exception e1){
e1.printStackTrace();
}
}
return str;
}
我将InputStream流和InputStreamReader流都单独定义引用是为了測试流关闭的问题,最后仅仅关闭最外层流,由于外层流关闭的时候就将包裹的流一并关闭了。见以下的BufferedReader类的close方法:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}
当中,in就是包裹的流。
以下贴post方法的代码。然后综合比較一下,代码:
public String doPost(String grantType, String appId, String secret){
HttpURLConnection conn = null;
InputStream is = null;
InputStreamReader reader = null;
BufferedReader br = null;
String str = "";
try {
URL url = new URL(ACCESS_TOKEN_WEIXIN);
conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);//默觉得false的,所以须要设置
conn.setUseCaches(false);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.connect();
OutputStream outStream = conn.getOutputStream();
DataOutputStream out = new DataOutputStream(outStream);
String params = "grant_type="+grantType+
"&appid="+appId+"&secret="+secret;
out.writeBytes(params);
out.close();
is = conn.getInputStream();
reader = new InputStreamReader(is, "UTF-8");
br = new BufferedReader(reader);
String readLine = "";
while((readLine=br.readLine())!=null){
str+=readLine+"\n";
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try{
if(br!=null){
br.close();
}
if(conn!=null){
conn.disconnect();
}
}catch(Exception e1){
e1.printStackTrace();
}
}
return str;
}
两相比較:
1.思路是一样的:首先建立链接对象(URL)->由链接对象得到代理对象(HttpUrlConnection)->设置一些链接參数->启动链接通道(conn.connect();)->进行输出\输入操作
2.get方法參数是带在链接上的,所以没有单独赋值操作。直接在启动链接通道后得到输入流就可以得到返回值
3.post方法參数不带在链接上,须要单独赋值(赋值是使用输出流来进行的)。须要将输出打开(conn.setDoOutput(true);)由于URLConnection默认输出是false。而input是默认打开的。故不用反复设置。
4.读取返回值方式一样。
在研究过程中,对于URLConnection如何得到的InputStream比較好奇。查看源代码为:
public InputStream getInputStream() throws IOException {
throw new UnknownServiceException("protocol doesn't support input");
}
所以非常迷惑,是jdk1.7 。等下来研究出来再补上来。
共勉!
-----------------------------------------------------------------
紧跟上面。对于jdk如何实现的getInputStream和getOutputStream以及其它一些方法,经过研究。最终找到了。接下来释疑:
须要注意到:
URL url = new URL(ACCESS_TOKEN_WEIXIN);
conn = (HttpURLConnection)url.openConnection();
这里得到HttpUrlConnection的时候是使用了强转得到的,故跟踪到URL类的openConnection方法内->
public URLConnection openConnection() throws java.io.IOException {
return handler.openConnection(this);
}
这里的handler定义在URL类的上方->
transient URLStreamHandler handler;
然后去寻找handler的赋值方法getURLStreamHandler。发现例如以下代码->
if (handler == null) {
String packagePrefixList = null;
packagePrefixList
= java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
protocolPathProp,""));
if (packagePrefixList != "") {
packagePrefixList += "|";
}
// REMIND: decide whether to allow the "null" class prefix
// or not.
packagePrefixList += JDK_PACKAGE_PREFIX;
StringTokenizer packagePrefixIter =
new StringTokenizer(packagePrefixList, "|");
while (handler == null &&
packagePrefixIter.hasMoreTokens()) {
String packagePrefix =
packagePrefixIter.nextToken().trim();
// do not try to instantiate the JDK gopher handler
// unless the system property had been explicitly set
if (protocol.equalsIgnoreCase(GOPHER) &&
packagePrefix.equals(JDK_PACKAGE_PREFIX) &&
!enableGopher) {
continue;
}
try {
String clsName = packagePrefix + "." + protocol +
".Handler";
Class cls = null;
try {
cls = Class.forName(clsName);
当中
JDK_PACKAGE_PREFIX
在类中定义的是:
private static final String JDK_PACKAGE_PREFIX = "sun.net.www.protocol";
再结合以下的
String clsName = packagePrefix + "." + protocol +
".Handler";
基本能够定位到handler类的实现类在sun.net.www.protocol.http.Handler。
然后百度搜索之后找到源代码(jdk下没有sun包的源代码)->
sun.net.www.protocol.http包的视图 Handler.java的源代码 ->
protected java.net.URLConnection openConnection(URL u)
throws IOException {
return openConnection(u, (Proxy)null);
} protected java.net.URLConnection openConnection(URL u, Proxy p)
throws IOException {
return new HttpURLConnection(u, p, this);
}
能够看到返回值是HttpURLConnection,可是发现该类中并没有引入java.net.HttpURLConnection类,故推測在Handler的同包下有一个同名类,果然发现该类,源代码 ->
public class HttpURLConnection extends java.net.HttpURLConnection
这是关建行,该类继承了java.net.HttpURLConnection类。所以返回该类能够由java.net.HttpURLConnection类的父类URLConnection接到,然后强转成java.net.HttpURLConnection类。设计十分巧妙->
@Override
public synchronized OutputStream getOutputStream() throws IOException { try {
if (!doOutput) {
throw new ProtocolException("cannot write to a URLConnection"
+ " if doOutput=false - call setDoOutput(true)");
} if (method.equals("GET")) {
method = "POST"; // Backward compatibility
}
if (!"POST".equals(method) && !"PUT".equals(method) &&
"http".equals(url.getProtocol())) {
throw new ProtocolException("HTTP method " + method +
" doesn't support output");
} // if there's already an input stream open, throw an exception
if (inputStream != null) {
throw new ProtocolException("Cannot write output after reading input.");
} if (!checkReuseConnection())
connect();
......
这就是getOutputStream的实现地方了,正好doOutput属性的设置也在这里起到了作用。
艾玛,最终找到实现的地方了。其它方法原理一致了。
略微整理下:整个的类流转过程就是:sun.net.www.protocol.http.HttpURLConnection转化成java.net.URLConnection,然后强转成java.net.HttpURLConnection。
晕乎~
HttpUrlConnection get和post简单实现(疑惑解决)的更多相关文章
- ASP.Net MVC_DotNetZip简单使用方法,解决文件压缩的问题[转]
准备工作: 在vs工具栏中找到NuGet 下载DotNetZip 现在就可以使用DotNetZip强大的类库了,在这里我给出一些简单的使用. ? 1 2 3 4 5 6 7 8 9 10 11 ...
- 虚拟机Linux不能上网简单有效的解决办法
对于刚开始接触Linux系统的用户来说,先使用虚拟机Linux学习是不错的选择.但是在用虚拟机上网的时候,总是出现这样那样的错误,到底该怎么办呢?本文笔者和大家分享一下虚拟机Linux不能上网的简单有 ...
- mysql安装到最后一步无响应的问题超简单最有效解决
mysql安装到最后一步无响应的问题超简单最有效解决 无论你是安装过还是没安装过,通过此方法都可以解决.之前我的机器和服务器就是都到最后一步卡住,上网搜索方法都无果.后自己尝试了很多次,亲测64位机和 ...
- ASP.Net MVC——DotNetZip简单使用,解决文件压缩问题。
准备工作: 在vs工具栏中找到NuGet 下载DotNetZip 现在就可以使用DotNetZip强大的类库了,在这里我给出一些简单的使用. public ActionResult Export() ...
- C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法
对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...
- 简单设置,解决使用webpack前后端跨域发送cookie的问题
最近用vue来做项目,用webpack来做前端自动化构建.webpack-dev-server会在本地搭建一个服务器,在和后端调试的时候,就会涉及到跨域的问题. 刚开始时,没有用vue-cli来构建项 ...
- < IOS > IOS适配,简单的分析解决一下
版权:张英堂 欢迎转载,转载请注明出处. 做的项目很多,一到适配的时候头就大了,IOS6,7的适配,屏幕的适配,当然还有下一步要出4.7屏幕,也要做适配....悲剧的移动端的人员. 怎么做一个通用的适 ...
- Vue.js devtool插件安装后无法使用的解决办法【最简单有效的解决方法】
在开发vue相关的项目时,使用vue devtools工具是一件极其有趣的事,你所有的操作都马上给你实时反馈. 然而有时候安装好的工具,在chrome中不显示. 在网上找过多次,一直没有找到有效解决方 ...
- HttpURLConnection和HttpClient的简单用法
HttpURLConnection的简单用法:先通过一个URL创建一个conn对象,然后就是可以设置get或者是post方法,接着用流来读取响应结果即可 String html = null; lon ...
随机推荐
- MVC 4 结合jquery.uploadify 上传实例
前言:由于今天公司源代码服务瘫痪,没法编写代码,利用这个有限的时间,做了一个小小的 基于MVC的图片上传demo,貌似近些年来MVC十分火爆,相关的demo也数不胜数,小弟就在这里打着MVC的旗子,狐 ...
- 一个不错的文章-【原创】2014年信息安全产品及厂家分类-SOC&SIEM安全厂家 | Srxh1314
转载:http://www.srxh1314.com/2014-sec-company-soc-siem.html http://www.bugsec.org/1598.html http://www ...
- 一些User-Agent
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)", "Mozilla/4.0 (compatible; MSIE ...
- Spring中注入List,Set,Map,Properties的xml文件配置方法
下面的例子展示了如何注入 List – <list/> Set – <set/> Map – <map/> Properties – <props/> ...
- 如何在一个工作站里创建多个工程(同一个xcode下面创建多个工程)
第一步,理解: 怎么会有一个xcode下面创建两个工程这一说呢,一个工程代表一个项目,意思就是有两个项目了.错.其实在一个窗口下面并不是两个工程,而是一个workspace 即一个工作站.在工作站里面 ...
- HDFS之HBase伪分布安装
1.HBase简介 HBase是Apache Hadoop中的一个子项目,Hbase依托于Hadoop的HDFS作为最基本存储基础单元,通过使用hadoop的DFS工具就可以看到这些这些数据 存储文件 ...
- Dijkstra算法求单源最短路径
Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店 ...
- Spring——AOP(面向切面编程)@AspectJ注解方式
一.什么是AOP? AOP: (Aspect Oriented Programming)即面向切面编程. 试想这样的场景:项目中需要在业务方法执行完打印日志记录.最笨的办法就是在每个方法核心业务执行完 ...
- linux杂记(六)档案权限
[KANO@kelvin ~]$ ls -al 总用量 drwx------. KANO KANO 10月 : . drwxr-xr-x. root root 9月 : .. drwxrwxr-x. ...
- 【转】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socket通讯 ...