超文本传输协定(HTTP。HyperTextTransferProtocol)是互联网上应用最为普遍的一种网络协议。php
所有的WWW文件都必须遵照这个标准。设计HTTP最初的目的是为了提供一种公布和接收HTML页面的方法。java
HTTP是一个client和server端请求和应答的标准(TCP)。client是终端用户,server端是站点。经过使用Web浏览器、网络爬虫或者其它的工具,client发起一个到server上指定port(默认port为80)的HTTP请求。编程
咱们称这个client为用户代理(useragent)。浏览器
应答的server上存储着一些资源,比方HTML文件和图像。咱们称这个应答server为源server。在用户代理和源server中间可能存在多个中间层,比方代理,网关,或者隧道(tunnel)。虽然TCP/IP协议是互联网上最流行的应用,HTTP协议并无规定必须使用它和基于它支持的层。缓存
其实,HTTP可以在不论什么其它互联网协议上。或者在其它网络上实现。HTTP仅仅假定其下层协议提供可靠的传输,不论什么可以提供这样的保证的协议都可以被其使用。安全
一般,由HTTPclient发起一个请求,创建一个到server指定port(默认是80port)的TCP链接。HTTPserver则在那个port监听client发送过来的请求。网络
一旦收到请求,server向client发回一个状态行,比方“HTTP/1.1200 OK”,和响应的消息,消息的消息体多是请求的文件、错误消息、或者其它一些信息。app
HTTP使用TCP而不是UDP的缘由在于打开一个网页必须传送不少数据。而TCP协议提供传输控制。按顺序组织数据,和错误纠正。异步
经过HTTP或者HTTPS协议请求的资源,由统一资源标识符(UniformResource Identifiers。URI)来标识。ide
HTTP/1.1协议中共定义了八种方法(有时也叫“动做”)来代表Request-URI指定的资源的不一样操做方式:
1)OPTIONS
返回server针对特定资源所支持的HTTP请求方法。也可以利用向Webserver发送'*'的请求来測试server的功能性。
2)HEAD
向server索要与GET请求相一致的响应,仅仅只是响应体将不会被返回。这一方法可以在没必要传输整个响应内容的状况下,就可以获取包括在响应消息头中的元信息。
3)GET
向特定的资源发出请求。
注意:GET方法不该当被用于产生“反作用”的操做中,好比在WebApplication中。当中一个缘由是GET可能会被网络蜘蛛等任意訪问。
參见安全方法
4)POST
向指定资源提交数据进行处理请求(好比提交表单或者上传文件)。数据被包括在请求体中。POST请求可能会致使新的资源的创建和/或已有资源的改动。
5)PUT
向指定资源位置上传其最新内容。
6)DELETE
请求server删除Request-URI所标识的资源。
7)TRACE
回显server收到的请求,主要用于測试或诊断。
8)CONNECT
HTTP/1.1协议中预留给可以将链接改成管道方式的代理server。
当某个请求所针对的资源不支持相应的请求方法的时候,server应当返回状态码405(MethodNot Allowed);当server不认识或者不支持相应的请求方法的时候,应当返回状态码501(NotImplemented)。
HTTPserver至少应该实现GET和HEAD方法。其它方法都是可选的。
固然。所有的方法支持的实现都应当符合下述的方法各自的语义定义。此外。除了上述方法。特定的HTTPserver还可以扩展本身定义的方法。
AndroidSDK提供了多个封装的类,可以很方便的实现基于HTML协议的编程。通常在,在Android中针对HTTP进行网络通讯有几种方式:一种是经过URL类获取网络资源。一种是使用HttpURLConnection类(通常经过用URL类的openConnection()方法建立一个HttpURLConnection对象)来实现。一种是使用Apache的HTTPclient组件HttpClient实现。如下会对这几种方式作详细的说明。
URL(UniformResourceLocator)对象表明统一资源定位器。它是指向互联网“资源”的指针。一般状况下,URL由协议名,主机,port,资源组成。例如如下:
http://www.your-host:80/index.php
URL类常用的方法有:
StringgetFile();//获取此URL的资源名 StringgetHost();//获取此URL的主机名 StringgetPath();//获取此URL的路劲 IntgetPort();//获取此URL的port号 StringgetProtocol();//获取此URL的协议名称 StringgetQuery();//获取此URL的查询字符串 URLConnectionopenConnection();//返回一个URLConnection对象 InputStreamopenStream();//打开链接,并返回一个用于读取该URL资源的InputStream |
URL对象提供了openStream()方法,就可以读取该URL资源的InputStream,很的方便。如下的代码演示样例。訪问了Web地址“http://www.google.cn/”。而且将server返回的HTML文本输出出来。
//import略 publicclass URLTest extends Activity { @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextViewtv = new TextView(this); StringmyString=""; try{ //定义获取文件内容的URL URLmURL = new URL("http://www.google.cn/"); //打开URL连接 //读取数据 InputStreamis = mURL.openStream(); BufferedInputStreambis = new BufferedInputStream(is); //使用用ByteArrayBuffer缓存 ByteArrayBufferbaf = new ByteArrayBuffer(50); intcurrent = 0; while((current= bis.read()) != -1) { baf.append((byte)current); } //将缓存的内容转化为String,用UTF-8编码 myString= EncodingUtils.getString(baf.toByteArray(), "UTF-8"); }catch(Exception e) { myString= e.getMessage(); } //设置屏幕显示 tv.setText(myString); this.setContentView(tv); } } |
需要特别注意的是,这里仅仅是简单举个样例简单说明怎样读取URL网络资源。可以看到。咱们将所有的代码都写到了Activity的onCreate()中。在真实的项目开发过程当中,这样的方式是有问题的。由于网络的堵塞,可能会出现ANR(ApplicationNot Response)错误,致使程序退出。正常的作法,应该是使用异步的方式请求网络数据。后面会有详细的样例说明详细怎样作。
经验分享: 为了不频繁读取字节流。提升读取效率,用BufferedInputStream缓存读到的字节流。 InputStreamis = mURL.openStream(); BufferedInputStreambis =new BufferedInputStream(is); //准备好BufferdInputStream后,咱们就可以用read方法读入网络数据 ByteArrayBufferbaf = new ByteArrayBuffer(50); intcurrent = 0; while((current= bis.read())! = -1) { baf.append((byte)current); } 由于读到的数据仅仅是字节流,没法直接显示到屏幕上,因此咱们得在显示以前将字节流转换为可读取的字符串。 假设读取的是.txt等文件是UTF-8格式的。就需要对数据进行专门的转换 myString= EncodingUtils.getString(baf.toByteArray(),"UTF-8"); |
HttpURLConnection继承于URLConnection。它在URLConnection的基础上提供了例如如下的便捷的方法。
voidsetResponseMethod(String method);//设置发送请求 intgetResponseCode();//获取server的响应代码 StringgetResponseMessage();//获取server的响应消息 StringgetResponseMethod();//获取发送请求 |
使用HttpURLConnection类訪问HTTP资源的基本过程例如如下:
1)建立URL以及HttpURLConnection对象。
2)设置链接參数。
3)链接到server。
4)向server写数据。
5)从server读取数据。
如下提供一段代码说明详细怎样实现。
try { //建立一个URL对象 URLurl = new URL(your_url); //建立一个URL链接。假设有代理的话可以指定一个代理。 URLConnectionconnection = url.openConnection(Proxy_yours); //对于HTTP链接可以直接转换成HttpURLConnection。这样就可以使用一些HTTP链接特定的方法。如setRequestMethod()等:HttpURLConnectionconnection = (HttpURLConnection)url.openConnection(Proxy_yours); //在開始和server链接以前,可能需要设置一些网络參数 connection.setConnectTimeout(10000); //链接到server connection.connect(); //与server交互: OutputStreamoutStream = connection.getOutputStream(); ObjectOutputStreamobjOutput = new ObjectOutputStream(outStream); objOutput.writeObject(newString(“this is a string…”)); objOutput.flush(); InputStreamin = connection.getInputStream(); //处理数据 省略详细代码… }catch (Exception e) { //网络读写操做每每会产生一些异常,因此在详细编写网络应用时 //最好捕捉每一个详细以採取相应措施 } |
ApacheHttpClient 是一个开源项目。它对java.net中的类进行了封装,弥补了java.net.*灵活性不足的缺点,更适合在Android中开发网络应用,支持client的HTTP编程,更加方便高效。
通常的。使用HttpClient进行网络开发的过程例如如下:
1)建立HttpClient对象。
2)假设需要发送GET请求,建立HttpGet对象;假设需要发送Post请求。建立HttpPost对象。
3)假设需要设置请求參数,可以使用HttpGet和HttpPost共同的setParams(HttpParamsparams)方法来加入请求參数。HttpPost还可以调用setEntity(HttpEntityentity)方法来设置。
4)调用HttpClient对象的execute(HttpUriRequestrequest)发送请求。运行该方法返回一个HttpResponse。
5)调用HttpResponse的getAllHeaders()。getHeaders(Stringname)等方法可获取响应头。调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象封装了响应的内容。
如下是一个详细的通用的网络链接类,包括了GET、POST的完整代码及注解。
//import略 publicclass HttpConnecter { /** *封装的Get方法 */ publicstatic String get(String uri) throws ClientProtocolException,IOException { //获取系统默认的HttpClient连接 HttpClienthttpClient = new DefaultHttpClient(); HttpGethttpGet = new HttpGet(uri); //发送GET请求 HttpResponsehttpResponse = httpClient.execute(httpGet); intstatusCode = httpResponse.getStatusLine().getStatusCode(); //获取server响应信息。200表明成功响应 if(statusCode >= 200 && statusCode < 400) { StringBuilderstringBuilder = new StringBuilder(); //httpResponse.getEntity().getContent()用来获取响应的内容 BufferedReaderreader = new BufferedReader(new InputStreamReader( httpResponse.getEntity().getContent(),"UTF-8")); for(String s = reader.readLine(); s != null; s = reader.readLine()) { //读出内容 stringBuilder.append(s); } reader.close(); Log.d("HttpConnecter","HTTPGET:" + uri.toString()); Log.d("HttpConnecter","Response:"+ stringBuilder.toString()); returnstringBuilder.toString(); } returnnull; } /** *封装的Post方法 */ publicstatic String post(String uri, List<NameValuePair>formparams) throwsClientProtocolException, IOException { HttpClienthttpClient = new DefaultHttpClient(); UrlEncodedFormEntityentity =new UrlEncodedFormEntity(formparams,"UTF-8"); HttpPosthttpPost = new HttpPost(uri); //设置请求參数 httpPost.setEntity(entity); //发送Post请求 HttpResponsehttpResponse = httpClient.execute(httpPost); intstatusCode = httpResponse.getStatusLine().getStatusCode(); if(statusCode >= 200 && statusCode < 400) { StringBuilderstringBuilder = new StringBuilder(); //httpResponse.getEntity().getContent()用来获取响应的内容 BufferedReaderreader = new BufferedReader(new InputStreamReader( httpResponse.getEntity().getContent(),"UTF-8")); for(String s = reader.readLine(); s != null; s = reader.readLine()) { stringBuilder.append(s); } reader.close(); Log.d("HttpConnecter","HTTPPOST:" + uri.toString()); Log.d("HttpConnecter","Response:"+ stringBuilder.toString()); returnstringBuilder.toString(); } returnnull; } } |
从上面的编程过程咱们可以看出。使用Apache的HttpClient更加简单,而且它比HttpURLConnection提供了不少其它的功能。因此普通状况下,咱们可以在项目中用HttpClient封装一些Get、Post、下载、上传的接口,以供其它代码直接调用。
经验分享: 在实现Android网络应用的开发过程当中。需要特别留意两个问题:一个是网络流量的问题。还有一个是网络链接可能不稳定的问题。 对于Android设备的上网方式。通常的有WIFI、3G、2G几种方式。 对于WIFI的用户。对于流量不会太在乎。而对于3G、甚至2G上网的用户来讲。流量是关系到用户钱包的大问题。因此,对于整个应用的设计,就要充分考虑流量的问题。 或者在项目后期作单独的优化工做。比方,假设应用中需要轮询server获取信息,那么咱们就可以依据用户的上网方式,本身主动调整轮询时间,为3G、2G的用户节省流量。这里仅仅是举这样一个样例。详细的,还要依据业务需求进行细致挖掘。 用户使用Android设备,通常都是碎片时间。多是在办公室,也多是在乘坐公交车或者地铁,网络信号未必会一直稳定。网络链接可能会时断时续。 咱们在设计网络应用的时候。就要充分考虑这样的状况。一个是要考虑怎样对网络链接异常进行处理,一个是要考虑网络恢复后怎样处理。 |