HTTP协议详解与Android相关基础网络编程

大量基础知识预警,大神请绕道~~

[TOC]
#### 一.从HTML说起

一.从HTML说起

HTML是Hyper Text Mark-up Language 的缩写,即“超文本标记语言”。注意这几个字——“超文本”是指页面内可以包含图片、链接、甚至音乐、程序等非文字元素"标记语言"——是一种将文本(Text)以及文本相关的其他信息结合起来,展现出关于文档结构和数据处理细节的计算机文字编码(维基百科),这个定义难理解的话想想我们熟悉的东西——我们做Android开发时写的xml文件就是标记语言,XML全称为可扩展标记语言(Extensible Markup Language,简称XML)。
  作为个人或者组织在万维网(web)上放置的开始页面称为“主页”,就像这张:

主页.png

主页中有指向其他相关页面或其他节点的指针(超链接)。所谓超链接就是一种统一资源定位器指针(Uniform Resource Locator),也就是传说中的URL(更通俗一点的说就是“网址”),通过点击激活它,可使浏览器方便快捷的访问其他的网页。嗯,这就是一排URL:

URL.png

设计HTML 语言的目的是为了能把存放在一台电脑中的文本或图形与另一台电脑中的文本或图形方便地联系在一起,形成有机的整体,人们不用考虑具体信息是在当前电脑上还是在网络的其它电脑上。这样,你只要使用鼠标在某一文档中点取一个图标,Internet就会马上转到与此图标相关的内容上去,而这些信息可能存放在网络的另一台电脑中.

二.什么是HTTP

1.什么是HTTP协议?

协议是指计算机通信网络中两台计算机之间进行通信的所必需共同遵守的规则。超文本传输协议(HTTP)是一种基于TCP链接的通信协议,是一个客户端和服务端请求和应答的标准,它允许将超文本标记语言(HTML)文档从web服务器传到客户端的浏览器。
  我们想浏览一个网站的时候,只要在浏览器的地址栏里输入网站的地址就可以了,例如www.baidu.com,但是在浏览器的地址栏里面出现的却是:http://www.baidu.com ,你知道为什么会多出一个“http”吗?
  我们在浏览器的地址栏里输入的网站地址也就是URL。就像每家每户都有一个门牌地址一样,每个网页也都有一个Internet地址。当你在浏览器的地址框中输入一个URL或是单击一个超级链接时,URL就确定了要浏览的地址。浏览器通过超文本传输协议(HTTP),将Web服务器上站点的网页代码提取出来,并翻译成漂亮的网页。因此,在我们认识HTTP之前,有必要先弄清楚URL的组成。

2.web服务器、浏览器、代理服务器

当我们打开浏览器,在地址栏中输入URL,跳转就会看到相应的网页。实际上当我们输入URL并敲击回车之后,我们的浏览器给web服务器发送了一个Request,web服务器接到这个Request之后做出相应的处理,生成相应的Response,然后发送给浏览器,浏览器解析Response中的HTML,我们就看到了网页:

图片1.png

我们的Request有可能是经过了代理服务器的,最后才抵达Web服务器:

图片2.png

代理服务器(Proxy Server)就是网络信息的中转站,其功能就是代理网络用户去获得网络信息,有了它浏览器不是直接到web服务器去取回网页,而是向代理服务器发出Request,由他取回浏览器所需要的信息并传递给你的浏览器。他有以下几种功能:
①提高访问速度
  大多数代理服务器都有缓存功能
②突破网络限制
  比如局域网对上网用户的端口、目的网站、协议、游戏、即时通讯软件等的限制,也就是翻墙了。比如A要访问C网站,但A到C网络出现问题,可以通过绕道,假设B是代理服务器,A可通过B, 再由B到C。
③隐藏自己的真实地址、身份信息
  隐藏自己的IP,防止被黑客攻击。通过分析指定IP地址,可以查询到网络用户的目前所在地。代理服务器知识是黑客基本功 ,黑客的很多活动都是通过代理服务器, 比如扫描、刺探,对局域网内机器进行渗透,黑客一般攻击的时候都是中转了很多级跳板,才攻击目标机器。隐藏了身份,保证了自己的安全。

3.URL详解

超链接URL地址用于描述一个网络上的资源,其基本格式如下:

schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
scheme             指定低层使用的协议(例如:http, https, ftp)
host                  HTTP服务器的IP地址或者域名
port#                 HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
path                  访问资源的路径
url-params          Url请求参数
query-string          发送给http服务器的数据
anchor-               锚

举个栗子(这个网址不知道当时是在哪找的,现在已经404了):

http://www.aspxfans.com:8080/news/index.asp?boardID=5&ID=24618&page=1#name

从上面的URL可以看出,一个完整的URL包括以下几部分:
(1)协议部分(scheme):该URL的协议部分为“http:”这代表网页使用的是HTTP协议。在Internet中有多种协议,如HTTP,FTP等等本例中使用的是HTTP协议。“//”为分隔符。
(2)域名部分(host):该URL的域名部分为“www.aspxfans.com”,通知aspxfans.com服务器显示web。一个URL中,也可以使用IP地址作为域名使用。
(3)端口部分(port#):跟在域名后面的是端口,域名和端口之间使用“:”作为分隔符。端口不是一个URL必须的部分,如果省略端口部分,将采用默认端口(80),此处的端口号是8080。
(4)虚拟目录部分(path访问资源的路径):从域名后的第一个“/”开始到最后一个“/”为止,是虚拟目录部分。虚拟目录也不是一个URL必须的部分。本例中的虚拟目录是“/news/”,为该服务器上的子目录。可以这么理解,域名对应的服务器就是C盘,虚拟目录就是Program Files等子文件夹。
(5)文件名部分(url-params):从域名后的最后一个“/”开始到“?”为止,是文件名部分,如果没有“?”,则是从域名后的最后一个“/”开始到“#”为止,是文件部分,如果没有“?”和“#”,那么从域名后的最后一个“/”开始到结束,都是文件名部分。
  本例中的文件名是“index.asp”,是我们要取的“/news/”文件夹中的一个HTML网页。文件名部分也不是一个URL必须的部分,如果省略该部分,则使用默认的文件名。
(6)参数部分(query-string)从“?”开始到“#”为止之间的部分为参数部分,又称搜索部分、查询部分。本例中的参数部分为“boardID=5&ID=24618&page=1”。参数可以允许有多个参数,参数与参数之间用“&”作为分隔符
(7)锚部分(anchor):从“#”开始到最后,都是锚部分。本例中的锚部分是“name”。锚部分也不是一个URL必须的部分。
  以上例子参考博客:http://blog.csdn.net/ergouge/article/details/8185219,我们可以分析一下这个博客的url:
该URL采用http协议,域名为blog.csdn.net,path资源路径(虚拟目录)为/ergouge/article/details/,这个类似于C:\Users\dell.android\avd一层一层的文件夹,而我们要获取的的“文件”(HTML网页)id即为8185219。

4.Http协议工作原理

Web浏览器和Web服务器之间是如何建立连接的呢?主要是通过以下四个步骤实现的。
  第一步,在客户端的浏览器中获取用户的输入内容。
  第二步,浏览器得到网址后,会将域名发送到DNS服务器上,进行域名解析,得到目的服务器的IP地址。
  第三步,使用Socket套接字来实现TCP/IP链接。从浏览器到服务器端口使用的是TCP/IP协议(网络层)来完成的。
  第四步,服务器的80端口监听客户端的链接,完成客户端到服务器的连接。
  上述四个步骤的具体实现过程如图所示。而在Internet内部可以通过三种方式来实现发送和接收数据,分别是Http协议、FTP协议和TCP/IP协议。

图片3.png

服务器返回客户端的内容有三种形式,分别是:
  (1)以Html代码的形式返回。
  (2)以xml字符串的形式返回。
  (3)以Json数据形式返回,从网络流量的角度考虑,Json方式要比xml方式好一些,且便于解析。

三.HTTP的报文结构

HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求,请求头包含请求的方法、URL、协议版本、以及包含请求修饰符、客户信息和内容的消息结构。服务器以一个状态行作为响应,相应的内容包括消息协议的版本,成功或者错误编码加上包含服务器信息、实体元信息以及可能的实体内容
  通常HTTP消息包括客户机向服务器的请求消息(Request)服务器向客户机的响应消息(Respone)。这两种类型的消息由一个起始行,一个或者多个头域,一个指示头域结束的空行和可选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。

1.通用头域

通用头域包含请求和响应消息都支持/包含的头域,通用头域包含Cache-Control、Connection、Date、Content-Type、Content-Transfer-Encoding等。对通用头域的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头域,一般将会作为实体头域处理。下面简单介绍几个经常使用的通用头域。
①Cache-Control头域:
  Cache-Control指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。
  请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached。
  响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。
各个消息中的指令含义如下:

Public:指示响应可被任何缓存区缓存。
Private:指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
no-cache:指示请求或响应消息不能缓存 。
no-store:用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
max-age:指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
min-fresh:指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
max-stale:指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

②HTTP Keep-Alive:
  Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。对于提供静态内容的网站来说,这个功能通常很有用。
  但是,对于负担较重的网站来说,这里存在另外一个问题:虽然为客户保留打开的连接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep- Alive功能对资源利用的影响尤其突出。
③Date头域:
  Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。
④Pragma头域:
  Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同。

2.Request 请求消息(RequestMessage)

先看Request 消息的结构,Request 消息分为3部分,第一部分叫请求行,第二部分叫http header, 第三部分是body。header和body之间有个空行,结构如下图:

Request 请求报文.png

如图,我们可以看到,一个完整的Request请求包括三部分——Frist line: GET/POST [URL路径] HTTP/[HTTP版本]+Header请求头域+Request Body。下面我们来一一讲解讲解这三个重要部分。
(1)请求行:GET/POST [URL路径] HTTP/[HTTP版本]
  Http协议定义了很多与服务器交互的方法,最基本的有4种:GET,POST,PUT,DELETE。 一个URL地址用于描述一个网络上的资源,而HTTP中的GET, POST, PUT, DELETE就对应着对这个资源的查,改,增,删4个操作。 我们最常见的就是GETPOST了。
  GET一般用于取回由Request-URI标识的信息(获取/查询资源信息)。
  POST一般用于更新资源信息(这里的更新值得是跟原来不一样,准确的说是新增。PUT才是严格意义上的修改/跟新),请求服务器接收包含在请求中的实体信息。可以用于提交表单,向新闻组、BBS、邮件群组和数据库发送消息。
我们看看GET和POST的区别:
  ①GET提交的数据会放在URL之后,以“?”分割URL和传输数据,参数之间以“&”相连,如EditPosts.aspx?name=test1&id=123456;POST方法是把提交的数据放在HTTP数据包的Body中
  ②GET提交的数据就在URL中,所以大小有限制(因为浏览器对URL的长度有限制);POST方法提交的数据没有限制。
  ③GET方式需要使用Request.QueryString来取得变量的值;POST方式通过Request.Form来获取变量的值。
  ④GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码。
(2)Header请求头域
  请求头域允许客户端向服务器传递关于客户端的附加信息,请求头域可能包含下列字段(笔者就整理了这么多,欢迎补充):

1)Accept:设置服务器返回的数据类型。
2)Accept-Languge:设置服务器返回的语言。
3)Accept-Encoding:设置服务器返回的压缩编码。
4)Accept-Charset:设置服务器返回的文字编码。
5)User-Agent:请求类型唯一标识。
6)Host头域 : Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须
    包含主机头域,否则系统会以400状态码返回。
7)Referer头域 : Referer头域允许客户端指定请求uri的源资源地址,这可以允许服务器生成回退链表,可用来登陆、优化cache
    等。他也允许废除的或错误的连接由于维护的目的被追踪。如果请求的uri没有自己的uri地址,Referer不能被发送。如果指
    定的是部分URL地址,则此地址应该是一个相对地址。
8)User-Agent头域:User-Agent头域的内容包含发出请求的用户信息。
9)Range头域: Range头域可以请求实体的一个或者多个子范围。
        例如, 表示头500个字节:bytes=0-499
        表示第二个500字节:bytes=500-999
        表示最后500个字节:bytes=-500
        表示500字节以后的范围:bytes=500-
        第一个和最后一个字节:bytes=0-0,-1
        同时指定几个范围:bytes=500-600,601-999
        但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是200(OK)。

(3)Request Body(只有POST请求的Body有意义)
  注意是POST,如果是GET的话这部分是空的,因为GET只是单纯的请求获取一些东西,他的参数都在URL中的那个"?"后面标明了;而POST则是要往服务器上发送一些东西(用于数据更新等),这个body就是我们发送的东西

3.Response应答消息

我们再看Response消息的结构, 和Request消息的结构基本一样。 同样也分为三部分,第一部分叫request line(请求行), 第二部分叫request header(请求头),第三部分是Respone body。 header和body之间也有个空行,结构如下图:

Respone报文格式.png

Response 消息中的第一行叫做状态行,由HTTP协议版本号,状态码,状态消息三部分组成。状态码和状态信息也就是上面表格中的200 OK,HTTP/1.1中有5类状态码,状态码由三位数字组成,第一个数字定义了响应的类别:

    1XX  提示信息 - 表示请求已被成功接收,继续处理
  2XX  成功 - 表示请求已被成功接收,理解,接受
  3XX  重定向 - 要完成请求必须进行更进一步的处理
  4XX  客户端错误 -  请求有语法错误或请求无法实现
  5XX  服务器端错误 -   服务器未能实现合法的请求
  
看看一些常见的状态码:
    200 OK:最常见的就是成功响应状态码200了, 这表明该请求被成功地完成,所请求的资源发送回客户端。
    302 Found:重定向,新的URL会在response中的Location中返回,浏览器将会使用新的URL发出新的Request。
        例如在IE中输入http://www.google.com. HTTP服务器会返回304, IE取到Response中Location header的新URL, 又重新发送了一个Request.
    304 Not Modified:代表上次的文档已经被缓存了, 还可以继续使用,
        提示:如果你不想使用本地缓存可以用Ctrl+F5强制刷新页面
    400 Bad Request  客户端请求与语法错误,不能被服务器所理解
    403 Forbidden  服务器收到请求,但是拒绝提供服务
    404 Not Found  请求资源不存在(输错了URL)

这里我们再解释一下Response消息中的请求头中几个常见参数:

1)Content-Type:是HTTP协议header中一个重要的参数,它用于标识发送或接收到的数据的类型,缺省值为" text/plain"。浏
    览器根据该参数来决定数据的打开方式。Content-Type使用的是 “主类型/子类型; 额外参数” ([type]/[subtype]; 
    parameter )的数值格式。主要类型有9种,分别是application、audio、example、image、message、model、
    multipart、text、video。
            “子类型” (subtype)用于指定"主类型"的详细形式。 其中以x-开头表示该类别尚未标准化。当客户端不能确定“子
    类型”时,会根据“主类型”来获取默认的子类型。 "额外参数" (parameter)用于指定请求/响应内容的字符编码格式。例如
    text/html;charset=utf-8;
        ①text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;默认是text/plain; 
            text/plain:纯文本,文件扩展名.txt
            text/html:HTML文本,文件扩展名.htm和.html
        ②multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据; 默认是multipart/mixed;
        ③image:用于传输静态图片数据;
            image/jpeg:jpeg格式的图片,文件扩展名.jpg
            image/gif:GIF格式的图片,文件扩展名.gif
        ④audio:用于传输音频或者音声数据;
            audio/x-wave:WAVE格式的音频,文件扩展名.wav
            audio/mpeg:MP3格式的音频,文件扩展名.mp3
        ⑤video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。
            video/mpeg:MPEG格式的视频,文件扩展名.mpg
        ⑥application:用于传输应用程序数据或者二进制数据; 默认是application/octet-stream; 
            application/zip:PK-ZIP格式的压缩文件,文件扩展名.zip
        ⑦message:用于包装一个E-mail消息;
2)Content-transfer-encoding:这条语句指明了编码转换的方式。Content-transfer-encoding的值有5种----
    "7bit"、"8bit"、"binary"、"quoted-printable"和"base64"----其中"7bit"是缺省值,即不用转化的ASCII字符。
3)Content-Length:返回数据流内容长度
4)Accept-Ranges:返回数据流压缩编码
5)Server:服务器类型

四.Android相关基础网络编程

之所以说是Android基础网络编程,是因为我们讲的东西都是比较原始的网络连接方式。真正的开发中我们要考虑很多性能问题,比如多线程等。我们常用的网络请求库如OKHttp等也就是封装的下面的内容,只不过考虑了很多性能问题,做了优化封装。

1.Android网络编程分为两种:基于HTTP协议与基于Socket

在计算机网络知识体系中,运输层的TCP(传输控制协议)把连接作为最基本的抽象。TCP的连接有两个端点,被称为Socket,通过IP地址+端口号来区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。Client进程和Server进程之间是通过Socket读写数据进行通信的。
  JDK的java.net包下有两个类:Socket和ServerSocket,在Client和Server建立连接成功后,两端都会产生一个Socket实例,操作这个实例,完成所需的会话,而程序员就通过这些API进行网络编程。 Socket连接过程分为三个步骤:服务器监听,客户端请求,连接确认Socket是对TCP/IP协议的封装,他本身不是什么协议,而是一个调用接口(API)TCP/IP只是一个协议栈,必须要具体实现,同时还要提供对外的操作接口,这就是Socket接口。通过Socket,我们才能使用TCP/IP协议,因此有了一系列我们知道的函数接口——connect、accept、send、read、write等。
  HTTP是应用层的协议,主要解决如何包装数据,应用层的协议有很多,除了HTTP协议以外还有FTP、TELNET等。Web使用HTTP协议作为应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将其发送到网络上。我们在传输数据时可以只使用(传输层)TCP/IP协议,但那样的话,如果没有应用层,便无法识别数据内容。
  注意Socket对TCP/IP协议的封装是跨传输层和应用层的(不然在客户端也无法调用)。
  由于通常情况下Socket链接即是TCP链接,因此Socket一旦建立,通信双方即可开始相互发送数据,直到双方链接断开,即不需要客户端给服务器发送请求,服务器端也可以主动向客户端发送数据;而HTTP链接使用的是“请求—响应”模式,不仅在请求时需要建立连接,而且客户端向服务器发出请求后服务器端才会回复数据,因此使用HTTP协议的客户端需要一个“心跳包”去定时询问服务器是否有新的数据并获取。
  因此,Socket看起来是比较方便的。但是他的缺点也是很明显的:客户端到服务器之间往往是要穿过多个中间点的,比如路由器、网关、防火墙等,很多防火墙会默认关闭长时间处于非活跃状态的链接,所以长时间没有数据更新的话很容易导致Socket链接中断,因此需要轮询告诉网络这个该链接处于活跃状态,利用Socket的客户端实现成本更高一些。
  一般来讲,像QQ、微信这种即时通讯类型的客户端就需要用Socket,而像一般论坛或者微博之类的用HTTP协议就可以了。

2.实现Android端的基于HTTP协议网络传输

在Android中进行http传输可以使用HttpURLConnection或者HttpClient类连接URL,但是HttpClient谷歌已经给他废了,所以我们只讲HttpURLConnection。
(1)“GET”方法:

GET读取网页流程.png

注:上述流程也是一般的网页爬虫爬取数据的流程。
第一步:指定URL资源并实现连接:

URL url = new URL(http://www.baidu.com);          //创建一个URL对象:
HttpURLConnection conn = (HttpURLConnection)url.openConnection(); //打开一个链接,用HttpURLConnection对象conn从网络中获取网页数据。

面这句代码这里实际上包含了两步:
URLConnection urlConnection = url.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection)urlConnection;
  URLConnection 与HttpURLConnection 使用的都是Java.net中的类,属于Java标准接口,后者继承自前者,差别在于后者只适用于http协议。从这里我们可以看出实际上 实现网络连接的是URLConnection类,这里是把这个类的对象强制转化为了HttpURLConnection类型,具体知识可以了解JAVA网络编程方面的知识。
第二步:设置连接参数的方法:

conn.setConnectTimeout(6*1000);     //设置连接超时,如果网络不好,Android系统会在设置的时间内收回资源终端操作
conn.setDoOutput(false);           //如果是POST请求,参数在正文中所以要允许输出流,如果是get请求不用输出了因为参数是在URL之后。
conn.setDoInput(true);                //响应数据的接收,所以我们要允许数据输入流。
conn.setUesCaches(false); //设置不用缓存,否则文件过的大的时候可能会造成内存溢出。
conn.setRequestMethod(“GET”);   //设置请求方式,注意不设的话默认情况下也是GET,因此setDoOutput默认情况下是false,setDoInput默认是true。
conn.setRequestProperty(
              URLEncoder.encode("Content-type","UTF-8"),
              URLEncoder.encode("application/x-java-serialized-object","UTF-8")
          );    //setRequestProperty这个函数中的参数也就是上面的Content-Type参数。

第三步:建立和远程资源之间的实际连接

conn.connect();              //建立一个TCP连接,这里直接封装好了,不用三次握手。
            //注意第二步中的那些属性都必须在connect()之前。

第四步:接收请求响应数据:
  对于GET请求,不用管outputStream,调用conn.getInputStream()方法来创建输入流即可接收Http的请求响应。如果是使用POST方法则需要调用conn.getOutputStream()方法来创建输出流,通过输出流将Http请求实体中的请求参数传递到服务器上。

InputStream inStream = conn.getInputStream();
InputStreamReader in = new InputStreamReader(inStream );    //无论是GET还是POST,HTTP的请求实际上直到调用
        //coon.getInputStream()才真正发送出去,对于GET而言不需要outputSream操作,因为已经DoOutput(false)了。
BufferedReader buffer = new BufferedReader(in);
If(conn.getResponseCode()!= 200){                  //对响应码进行判断
     Throw new RuntimeException(“请求URL失败”);
}else{
     //输入流读取字节,再将它们转化成字符,读取内容:
     String inputLine = null;
     String resultData = null;
     While((inputLine = buffer.readeLine())!=null){
           resultData += inputLine;        //利用循环来读取数据
     }
}
conn.disconnect();                        //及时关闭
(2)"POST”方法

POST用法与GET方法基本一致,不同的是POST是要往服务器端发送数据(用于数据更新等),它的参数是放在HTTP正文内的,所以这个时候就要用到conn.getOutputStream();方法。
  还有就是GET请求可以缓存(当然也可以手动不缓存),Post请求不能缓存——至于为什么不能缓存,这个过于博大精深,有待于进一步研究。
第一步:指定URL资源并实现连接

URL url = new URL(http://localhost:8080/TestHttpURLConnectionPro.do);     
HttpURLConnection conn = (HttpURLConnection)url.openConnection();

第二步:指定链接参数的方法

conn.setDoOutput(true);      //设置是否向HttpURLConnection输出,这个是post请求,参数要放在http协议正文中,所以必须设为true,默认状态下为false.
conn.setDoInput(true);      //设置是否从HttpURLConnection读入信息。
conn.setUesCaches(false);   //POST不能用缓存
conn.setRequestProperty(“Content-type”,”application/x-iava-serialized-object”); //上面这一步也要看我们与服务器之间的约定
conn.setRequestMethod(“POST”); 

第三步:建立和远程资源之间的实际连接
  OutputStream不是一个网络流,充其量只是一个字符串流,往其中写的东西不会立即发送到网络上,而是存在于内存缓存区等到outputStream流关闭时,根据其内容生成HTTP正文
  至此,http请求的东西已经全部准备好了,在第四步调用getInputStream()函数调用的时候,就会把准备好的http请求发送到服务器,并且返回一个输入流,用于读取服务器对于此次请求的返回信息
  由于http请求在getInputStream()函数调用的时候已经发送出去了(包括http头和正文body),因此在这之后对conn对象进行设置(对http头的信息修改)或者写入outputStream(对正文进行修改)都是没有意义的,执行这些操作会发生异常。

conn.connect();
OutputStream outStream = conn.getOutputStream();    //此处OutputStream会隐含进行connect,所以上面的connect()方法可以不用写。
DataOutputStream out= new DataOutputStream (outStream );

第四步:写入并发送我们的实际数据

String content = “firstname”+URLEncoder.encode(“LIU”,”UTF-8”);
out.writeBytes(content);   //向对象流写入数据,这些数据将存到内存缓冲区
out.flush();       //刷新对象输出流,将任何字节都写入潜在流中。
out.close();      //关闭流对象,此时不能再向对象流写入任何数据,先前写入的数据存在于内存缓冲区中,在调用下边的getInputStream()函数时才把准备好的请求发送到服务器。

InputStream inStream = conn.getInputStream();    //注意啦,这里和GET请求中的一样
InputStreamReader in = new InputStreamReader(inStream) ;//getInputStream()这个函数的作用有两个,一个是发送
                //请求(包括上面我们写入的数据),另一个是读取响应,即便是POST,你给服务器发送数据之后他还是要给你
                //传一些数据回来的,不如说更新成功之类的。
BufferedReader buffer = new BufferReader(in);
if(conn.getResponseCode()!= 200){
     Throw new RuntimeException(“请求URL失败”);
}else{
     String inputLine = null;
     String resultData = null;
     While((inputLine = buffer.readeLine())!=null){
           resultData += inputLine;
     }
}
conn.disconnect();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 一、概念(载录于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434阅读 8,295评论 6 152
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Http协议详解 标签(空格分隔): Linux 声明:本片文章非原创,内容来源于博客园作者MIN飞翔的HTTP协...
    Sivin阅读 5,152评论 3 82
  • PS:简书的网址真不是给人看的。。。我单独开了一个网址可以重定向到我的简书主页。博客地址:flutterall.c...
    徐爱卿阅读 6,835评论 21 97
  • 本文整理自MIN飞翔博客 [1] 1. 概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或...
    HoyaWhite阅读 2,577评论 2 20