`

关于httpurlconnection的认识

阅读更多
原文链接地址:
http://www.blogjava.net/supercrsky/articles/247449.html

针对JDK中的URLConnection连接Servlet的问题,网上有虽然有所涉及,但是只是说明了某一个或几个问题,是以FAQ的方式来解决的,而且比较零散,现在对这个类的使用就本人在项目中的使用经验做如下总结:
1:> URL请求的类别:
分为二类,GET与POST请求。二者的区别在于:
     a:) get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给servlet,
     b:) post与get的不同之处在于post的参数不是放在URL字串里面,而是放在http请求的正文内。
2:> URLConnection的对象问题:
URLConnection的对象,如下代码示例:

// 下面的index.jsp由<servlet-mapping>映射到
// 一个Servlet(com.quantanetwork.getClientDataServlet)
// 该Servlet的注意点下边会提到

URL url = new URL("http://localhost:8080/TestHttpURLConnectionPro/index.jsp"); 

URLConnection rulConnection = url.openConnection();// 此处的urlConnection对象实际上是根据URL的 
          // 请求协议(此处是http)生成的URLConnection类 
          // 的子类HttpURLConnection,故此处最好将其转化 
          // 为HttpURLConnection类型的对象,以便用到 
          // HttpURLConnection更多的API.如下: 

HttpURLConnection httpUrlConnection = (HttpURLConnection) rulConnection; 


3:> HttpURLConnection对象参数问题

// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在 
// http正文内,因此需要设为true, 默认情况下是false; 
httpUrlConnection.setDoOutput(true); 

// 设置是否从httpUrlConnection读入,默认情况下是true; 
httpUrlConnection.setDoInput(true); 

// Post 请求不能使用缓存 
httpUrlConnection.setUseCaches(false); 

// 设定传送的内容类型是可序列化的java对象 
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException) 
httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object"); 

// 设定请求的方法为"POST",默认是GET 
httpUrlConnection.setRequestMethod("POST"); 

// 连接,从上述第2条中url.openConnection()至此的配置必须要在connect之前完成, 
        httpUrlConnection.connect(); 


4:>  HttpURLConnection连接问题:
// 此处getOutputStream会隐含的进行connect(即:如同调用上面的connect()方法, 
// 所以在开发中不调用上述的connect()也可以)。 
OutputStream outStrm = httpUrlConnection.getOutputStream(); 


5:> HttpURLConnection写数据与发送数据问题:
// 现在通过输出流对象构建对象输出流对象,以实现输出可序列化的对象。 
ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStrm); 

// 向对象输出流写出数据,这些数据将存到内存缓冲区中 
objOutputStrm.writeObject(new String("我是测试数据")); 

// 刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream) 
objOutputStm.flush(); 

// 关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区中, 
// 在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器 
objOutputStm.close(); 

// 调用HttpURLConnection连接对象的getInputStream()函数, 
// 将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。 
InputStream inStrm = httpConn.getInputStream(); // <===注意,实际发送请求的代码段就在这里 

// 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义, 
// 既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据. 
// 因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、 
// 重新发送数据(至于是否不用重新这些操作需要再研究) 
objOutputStm.writeObject(new String("")); 
httpConn.getInputStream(); 


总结:a:) HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
    无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
       b:) 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,
    对connection对象的一切配置(那一堆set函数)
    都必须要在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不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,
    而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。
    至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求
    正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http
    请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数
    之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)
    都是没有意义的了,执行这些操作会导致异常的发生。

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();



HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);

其中: sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)

例如:
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTime

Java中可以使用HttpURLConnection来请求WEB资源。
HttpURLConnection对象不能直接构造,需要通过URL.openConnection()来获得HttpURLConnection对象,示例代码如下:

String szUrl = "http://www.ee2ee.com/";
URL url = new URL(szUrl);
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection(); 


HttpURLConnection是基于HTTP协议的,其底层通过socket通信实现。如果不设置超时(timeout),在网络异常的情况下,可能会导致程序僵死而不继续往下执行。可以通过以下两个语句来设置相应的超时:
System.setProperty("sun.net.client.defaultConnectTimeout", 超时毫秒数字符串);
System.setProperty("sun.net.client.defaultReadTimeout", 超时毫秒数字符串);

其中: sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)

例如:
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTimeout", "30000");

JDK 1.5以前的版本,只能通过设置这两个系统属性来控制网络超时。在1.5中,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)

例如:
HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();
urlCon.setConnectTimeout(30000);
urlCon.setReadTimeout(30000); 


需要注意的是,笔者在JDK1.4.2环境下,发现在设置了defaultReadTimeout的情况下,如果发生网络超时,HttpURLConnection会自动重新提交一次请求,出现一次请求调用,请求服务器两次的问题(Trouble)。我认为这是JDK1.4.2的一个bug。在JDK1.5.0中,此问题已得到解决,不存在自动重发现象。out", "30000");
分享到:
评论

相关推荐

    认识网络爬虫(含实例源码)

    ### 认识网络爬虫(含实例源码) #### 全面剖析网络爬虫 网络爬虫,又称网络蜘蛛或网络机器人,是一种自动化的程序,用于遍历互联网上的网页,并从中提取所需信息。搜索引擎如百度、Google就是利用网络爬虫技术来...

    Android Cookie 深度理解

    总结,理解并正确使用Cookie对于Android开发者来说至关重要,无论是为了实现用户登录状态的保持,还是提供个性化的用户体验,都需要对Cookie有深入的认识。在实际开发中,应遵循最佳实践,确保用户数据的安全性和...

    应用源码http、udp、tcp网络交互组件.zip

    学习这些源码可以帮助开发者理解网络通信的基本原理,掌握Android中网络组件的使用,同时对TCP和UDP的特性有深入认识。对于毕业设计和代码学习者,这样的实践项目能提升实际编程技能,增强问题解决能力。 在使用...

    Http发送请求

    HTTP(超文本传输协议)是互联网上应用最为广泛的一种网络协议,它...无论是手动配置HTTP请求还是编写代码实现,都需要对这些基础知识有清晰的认识。通过上述介绍,你应该能够更好地理解和应用HTTP协议进行网络通信。

    QQ注册登陆SWING界面模拟

    Swing是Java提供的一个用于创建图形用户界面(GUI)的工具包,它允许开发者构建美观、交互性强的桌面应用。...通过这个项目,开发者可以深入理解Java GUI编程,提高网络编程技能,并对用户认证过程有更直观的认识。

    Android公司培训

    学员将学习到如何使用HttpURLConnection、OkHttp或Retrofit进行网络请求,处理JSON数据,并实现异步加载,提高用户体验。 除此之外,Android的生命周期管理和异常处理也是关注的重点。理解各个Activity状态的变迁和...

    google android开发入门与实战原书和示例源码

    "程序,让开发者对Android开发有个直观的认识。接着,深入讲解Android应用的基本结构,如Activity、Intent和Layout,这些都是构建用户界面的关键元素。 在UI设计部分,你会学习如何使用XML布局文件创建各种控件,如...

    安卓Android源码——安卓高仿手机QQ(客户端服务端).zip

    【标题】中的“安卓Android源码——安卓高仿手机QQ(客户端服务端).zip”表明这是一个关于Android平台的源...通过深入分析和理解这份源码,可以掌握一套完整的Android应用开发流程,同时对服务端开发也有一定的认识。

    Java项目实战-基于java博网即时通讯软件的设计与实现(附源码,部署说明).zip

    本项目实战是关于使用Java语言开发一款博网即时通讯软件,旨在帮助开发者深入理解Java在实际项目中的应用,特别是涉及到网络通信和多线程技术。这个项目提供了完整的源码,并附带了详细的部署说明,方便学习者进行...

    android培训学习心得体会.doc

    在网络通信上,学习了使用HttpURLConnection和OkHttp进行HTTP请求,以及使用Retrofit和Volley等网络库进行更高级的API调用。 在培训中,我还接触到了Android的异步处理,如AsyncTask和Handler/Looper机制,这些对于...

    android视频教程部分源码

    通过分享这些源码,开发者可以对Android应用的开发过程有更直观的认识,同时也提供了动手实践的机会。 1. **progressBarTest**: 这部分源码可能涉及Android UI设计,尤其是进度条(ProgressBar)的使用。在Android...

    《Android应用开发揭秘》源码

    在移动应用中,网络通信是常见的功能,开发者需要了解如何使用HttpURLConnection或者第三方库如Volley、Retrofit等进行网络请求,并能正确处理数据的解析和错误的捕获。同时,考虑到性能,网络操作通常在后台线程...

    Android应用开发揭秘(杨丰盛)源码 part3

    在本资源中,“Android应用开发揭秘(杨丰盛)源码 part3”是关于Android应用程序开发的一个重要学习资料,由知名作者杨丰盛提供。这部分源码可能包含了书中的实例项目,旨在帮助读者深入理解Android应用开发的核心...

    Android开发PPT教程

    总的来说,《Android开发PPT教程》将带领学习者从零开始,逐步构建起对Android开发的全面认识,覆盖了从基础到高级的各个层面,是Android开发者成长道路上的一份宝贵资料。通过系统学习和实践,不仅可以掌握开发技能...

    疯狂Android讲义(第2版)完整清晰版

    这部分内容有助于初学者建立对Android系统的整体认识,理解各个组件之间的关系。 2. **环境搭建与开发工具**:讲解了如何安装和配置Android Studio,设置SDK,以及使用Android调试桥(ADB)进行设备或模拟器的管理...

    深入浅出Google Android PDF

    这本书会详细解释这些组成部分的作用及其相互关系,让读者对Android的运行机制有深入的认识。 Android应用程序主要由Java语言编写,因此了解Java基础至关重要。书中将介绍Java编程的基本语法、面向对象编程的概念...

    【Java毕业设计】大学本科毕业设计-使用Java语言开发的简单的HTTP服务器.zip

    在本Java毕业设计项目中,学生将学习到如何利用Java编程语言实现一个简单的HTTP服务器,这对于理解网络编程、HTTP协议以及服务器端...通过实际操作,不仅可以掌握Java编程技能,还能对互联网的工作方式有更深刻的认识。

    android5天课程

    通过这五天的密集学习,你将对Android开发有一个全面的认识,能够编写出具有基本功能的应用程序。每个Demo都是一个实战练习,帮助巩固所学知识,让你在实践中成长。继续探索,持续学习,你将成为一名熟练的Android...

    Android地图相关程序源码

    开发者可能需要使用HttpURLConnection或OkHttp等网络库来发送GET或POST请求,然后解析返回的JSON或XML数据,将线路信息展示在UI上。解析工作通常需要用到Gson、Jackson或自定义XML/JSON解析器。 其次,**获取GPS...

Global site tag (gtag.js) - Google Analytics