近期研究微信的公众平台开发。须要和微信的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简单实现(疑惑解决)的更多相关文章

  1. ASP.Net MVC_DotNetZip简单使用方法,解决文件压缩的问题[转]

    准备工作: 在vs工具栏中找到NuGet   下载DotNetZip   现在就可以使用DotNetZip强大的类库了,在这里我给出一些简单的使用. ? 1 2 3 4 5 6 7 8 9 10 11 ...

  2. 虚拟机Linux不能上网简单有效的解决办法

    对于刚开始接触Linux系统的用户来说,先使用虚拟机Linux学习是不错的选择.但是在用虚拟机上网的时候,总是出现这样那样的错误,到底该怎么办呢?本文笔者和大家分享一下虚拟机Linux不能上网的简单有 ...

  3. mysql安装到最后一步无响应的问题超简单最有效解决

    mysql安装到最后一步无响应的问题超简单最有效解决 无论你是安装过还是没安装过,通过此方法都可以解决.之前我的机器和服务器就是都到最后一步卡住,上网搜索方法都无果.后自己尝试了很多次,亲测64位机和 ...

  4. ASP.Net MVC——DotNetZip简单使用,解决文件压缩问题。

    准备工作: 在vs工具栏中找到NuGet 下载DotNetZip 现在就可以使用DotNetZip强大的类库了,在这里我给出一些简单的使用. public ActionResult Export() ...

  5. C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法

    对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...

  6. 简单设置,解决使用webpack前后端跨域发送cookie的问题

    最近用vue来做项目,用webpack来做前端自动化构建.webpack-dev-server会在本地搭建一个服务器,在和后端调试的时候,就会涉及到跨域的问题. 刚开始时,没有用vue-cli来构建项 ...

  7. < IOS > IOS适配,简单的分析解决一下

    版权:张英堂 欢迎转载,转载请注明出处. 做的项目很多,一到适配的时候头就大了,IOS6,7的适配,屏幕的适配,当然还有下一步要出4.7屏幕,也要做适配....悲剧的移动端的人员. 怎么做一个通用的适 ...

  8. Vue.js devtool插件安装后无法使用的解决办法【最简单有效的解决方法】

    在开发vue相关的项目时,使用vue devtools工具是一件极其有趣的事,你所有的操作都马上给你实时反馈. 然而有时候安装好的工具,在chrome中不显示. 在网上找过多次,一直没有找到有效解决方 ...

  9. HttpURLConnection和HttpClient的简单用法

    HttpURLConnection的简单用法:先通过一个URL创建一个conn对象,然后就是可以设置get或者是post方法,接着用流来读取响应结果即可 String html = null; lon ...

随机推荐

  1. background:url 的使用方法

    #pingfen li{ width:27px; float:left; height:28px; cursor:pointer; background:url( ; list-style:none; ...

  2. codeforces 8C. Looking for Order 状压dp

    题目链接 给n个物品的坐标, 和一个包裹的位置, 包裹不能移动. 每次最多可以拿两个物品, 然后将它们放到包里, 求将所有物品放到包里所需走的最小路程. 直接状压dp就好了. #include < ...

  3. C#的线程池的那些事

    最近在做站时发现,线程池的问题很棘手,所以总结了一篇关于线程池的文章,原文地址:http://www.shuonar.com/blog/ac16496b-87ec-4790-a9ea-d69bbffa ...

  4. Umbraco模型默认属性

    Media Model的属性: umbracoFileumbracoWidthumbracoHeightumbracoBytesumbracoExtension

  5. QCA4002/QCA4004 为主流家电和消费电子产品推出低功耗Wi-Fi平台

    美国高通公司日前宣布,其子公司高通创锐讯推出全新芯片系列,这是低功耗Wi-Fi解决方案系列的一部分,可连接组成物联网的各种设备.QCA4002和QCA4004网络平台在芯片上纳入IP堆栈及完整的网络服 ...

  6. 获取考试成绩的sql语句

    as score,t_answer.id,t_answer.exams_name,t_answers.answer_id,t_answers.questions_id,t_answers.questi ...

  7. [Leetcode][Python]21: Merge Two Sorted Lists

    # -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 21: Merge Two Sorted Listshttps://oj.le ...

  8. Android_Intent意图详解

    本博文为子墨原创,转载请注明出处! http://blog.csdn.net/zimo2013/article/details/11863857 1.Intent作用 Intent是一个将要执行的动作 ...

  9. c++链接数据库测试,中文有问题

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <Windows.h& ...

  10. 网易云课堂_C语言程序设计进阶_第5周:链表

    5.1可变数组 5.2链表 5.1可变数组 Resizable Array Think about a set of functions that provide a mechanism of res ...