前面我们学习的Android开发基本都是本地的开发,没有与服务器进行交互。这一篇开始,我们开始学习android的网络编程技术,Android网络交互基本有三种方式:数据上传、数据下载、数据浏览。在实际开发中,我们与服务器交互基本都需要通过网络协议,所以学好网络协议是非常重要的,网络协议有很多,但是我们在Android开发中经常用到的是HTTP协议,这是互联网应用最广泛的一种网络协议,下面我们学习一下这个HTTP协议吧!
1、HTTP协议简介
1.1、什么是HTTP协议?
HTTP全称HyperText Transfer Protocol中文为超文本传输协议,HTTP是互联网中最常用的一种通信协议,它允许将HTML(超文本标记文档)从服务端传输到客户端的浏览器,目前我们使用HTTP协议版本是1.1版本。HTTP1.0和HTTP1.1不同就是客户端跟服务端建立连接之后,客户端能获得的WEB资源数不同,1.0版本只能获得一个WEB资源,1.1可以获得多个WEB资源。
HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。HTTP协议的主要特点可概括如下:
-
1.支持客户/服务器模式。
-
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
-
3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
-
4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
-
5.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
1.2、HTTP协议之URL
HTTP URL格式如下:
schema://host[:port#]/path/.../[;url-params][?query-string][#anchor]
URL解析:
-
scheme:指定低层使用的协议(例如:http, https, ftp)
-
host:HTTP服务器的IP地址或者域名,主机
-
port#:HTTP服务器的默认端口是80,这种情况下端口号可以省略。如果使用了别的端口,必须指明,例如 http://www.cnblogs.com:8080/
-
path:访问资源的路径
-
url-params:请求参数,可以没有
-
query-string:发送给http服务器的数据
-
anchor:锚
例如,下面就是一个完整的URL地址:
http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html
2、HTTP协议请求和响应
2.1、HTTP协议之请求
HTTP协议的一个完整请求包含三部分:请求行;消息报头;请求正文,下面我们分别学习一下HTTP协议的请求:
下面我们先看一个完整的请求
GET http://www.hao123.com/ HTTP/1.1
Host: www.hao123.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2763.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: BDUSS=nFtQXZ2aH5XOGpmWGdjM09Fb1VXeDZ6ZnllbVBJMVRMaTU4dWNPNDlNa0FSS1ZYQVFBQUFBJCQAAAAAAAAAAAEAAACAl4Av1cV6aGFuZ2h1YXdlbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3fVcAt31XQ; yun_tip=1; scrollflag=1468980654236; ft=1; tvtip_notshow=1_1; BAIDUID=D63A0D8DD3EA54BE68D0F8987678C578:FG=1; FLASHID=7E505E28B6D121D76C732340528F7E6E:FG=1; tnwhiteft=XzFYUBclcWbLPW64n1fsgv99Udqsuzc_cMw1cWCkPjm4nHRYP1c4xf; famous_banner=%7B%7D; HUM=; HUN=; newloc=%7C%7C; loc2=1%7C%E5%B9%BF%E4%B8%9C%7C%E5%B9%BF%E5%B7%9E; mtip=1; __bsi=7540217970290249139_00_59_R_R_4_0303_c02f_Y
2.1.1、请求行
请求行的格式如下:Method Request-URI HTTP-Version CRLF,解析如下: Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符)。
HTTP协议提供的请求方法解析如下:
- GET 请求获取Request-URI所标识的资源
- POST 在Request-URI所标识的资源后附加新的数据
- HEAD 请求获取由Request-URI所标识的资源的响应消息报头
- PUT 请求服务器存储一个资源,并用Request-URI作为其标识
- DELETE 请求服务器删除Request-URI所标识的资源
- TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
- CONNECT 保留将来使用
- OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
请求行实例:
GET http://www.hao123.com/ HTTP/1.1
2.1.2、消息报头
后面会详细介绍
2.1.3、请求正文
请求正文就是客户端向服务器发送请求的内容
2.2、HTTP协议之响应
服务端在接收和解释请求消息后,服务器返回一个HTTP响应消息。HTTP响应也是由三个部分组成,分别是:状态行、消息报头、响应正文
下面是一个响应:
HTTP/1.1 302 Found
Content-Encoding: gzip
Content-Type: text/html;charset=UTF-8
Date: Fri, 22 Jul 2016 02:38:32 GMT
Lfy: cq02.11
Location: https://www.hao123.com/
Server: BWS/1.0
Set-Cookie: fromhttp=1; path=/; domain=www.hao123.com
Set-Cookie: hz=0; path=/; domain=www.hao123.com
Sfy: cq02.11
Vary: Accept-Encoding
Content-Length: 0
2.2.1、状态行
状态行格式如下:HTTP-Version Status-Code Reason-Phrase CRLF。其中,HTTP-Version表示服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-Phrase表示状态代码的文本描述。
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:
- 1xx:指示信息–表示请求已接收,继续处理
- 2xx:成功–表示请求已被成功接收、理解、接受
- 3xx:重定向–要完成请求必须进行更进一步的操作
- 4xx:客户端错误–请求有语法错误或请求无法实现
- 5xx:服务器端错误–服务器未能实现合法的请求
常见状态代码、状态描述、说明:
- 200 OK //客户端请求成功
- 400 Bad Request //客户端请求有语法错误,不能被服务器所理解
- 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
- 403 Forbidden //服务器收到请求,但是拒绝提供服务
- 404 Not Found //请求资源不存在,eg:输入了错误的URL
- 500 Internal Server Error //服务器发生不可预期的错误
- 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
响应行实例:
HTTP/1.1 302 Found
2.2.2、消息报头
后面会详细介绍
2.2.3、响应正文
响应正文就是服务器返回的资源的内容
3、HTTP协议之消息报头
HTTP消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行(对于请求消息,开始行就是请求行,对于响应消息,开始行就是状态行),消息报头(可选),空行(只有CRLF的行),消息正文(可选)组成。
HTTP消息报头包括普通报头、请求报头、响应报头、实体报头,下面分别介绍一下:
每一个报头域都是由名字+”:”+空格+值 组成,消息报头域的名字是大小写无关的。
3.1、普通报头
在普通报头中,有少数报头域用于所有的请求和响应消息,但并不用于被传输的实体,只用于传输的消息。
-
Cache-Control:用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。
-
请求时的缓存指令包括: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、s-maxage 。 -
Date:普通报头域表示消息产生的日期和时间。
-
Connection:普通报头域允许发送指定连接的选项。例如指定连接是连续,或者指定“close”选项,通知服务器,在响应完成后,关闭连接。
3.2、请求报头
允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。常用的请求报头如下:
-
Accept:Accept请求报头域用于指定客户端接受哪些类型的信息。Accept:image/gif,表明客户端希望接受GIF图象格式的资源;Accept:text/html,表明客户端希望接受html文本。
-
Accept-Charset:Accept-Charset请求报头域用于指定客户端接受的字符集。Accept-Charset:iso-8859-1,gb2312.如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。
-
Accept-Encoding:Accept-Encoding请求报头域类似于Accept,但是它是用于指定可接受的内容编码。Accept-Encoding:gzip.deflate.如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受。
-
Accept-Language:Accept-Language请求报头域类似于Accept,但是它是用于指定一种自然语言。Accept-Language:zh-cn.如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。
-
Authorization:Authorization请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进行验证。
-
Host(发送请求时,该报头域是必需的):Host请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的。
-
eg:我们在浏览器中输入:http://www.guet.edu.cn/index.html。浏览器发送的请求消息中,就会包含Host请求报头域,如:Host:www.guet.edu.cn,此处使用缺省端口号80,若指定了端口号,则变成:Host:www.guet.edu.cn:指定端口号
-
User-Agent:User-Agent这个报头域向服务器提供客户端使用的操作系统名称、操作系统版本、浏览器名称、浏览器版本等信息,这个报头域不是必须的。
请求报头实例:
GET / HTTP/1.1
Host: www.hao123.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2763.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: BDUSS=nFtQXZ2aH5XOGpmWGdjM09Fb1VXeDZ6ZnllbVBJMVRMaTU4dWNPNDlNa0FSS1ZYQVFBQUFBJCQAAAAAAAAAAAEAAACAl4Av1cV6aGFuZ2h1YXdlbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC3fVcAt31XQ; yun_tip=1; scrollflag=1468980654236; BAIDUID=62BBD52ECDCE80FEA5178C988C501DAF:FG=1; FLASHID=7E505E28B6D121D76C732340528F7E6E:FG=1; ft=1; tvtip_notshow=1_1; tnwhiteft=XzFYUBclcWbLPW64n1fsgv99Udqsuzc_cMw1cWCkPjm4nHR1rjnLxf; famous_banner=%7B%7D; HUM=; HUN=; mtip=1; newloc=%7C%7C; loc2=1%7C%E5%B9%BF%E4%B8%9C%7C%E5%B9%BF%E5%B7%9E; __bsi=11355086620082288439_00_59_R_R_3_0303_c02f_Y
3.3、响应报头
响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和对Request-URI所标识的资源进行下一步访问的信息。常用的响应报头如下:
-
Location:Location响应报头域用于重定向接受者到一个新的位置。Location响应报头域常用在更换域名的时候。
-
Server:Server响应报头域包含了服务器用来处理请求的软件信息。与User-Agent请求报头域是相对应的。Server响应报头域的一个例子:Server:Apache-Coyote/1.1
-
WWW-Authenticate:WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,客户端收到401响应消息时候,并发送Authorization报头域请求服务器对其进行验证时,服务端响应报头就包含该报头域。eg:WWW-Authenticate:Basic realm=”Basic Auth Test!” //可以看出服务器对请求资源采用的是基本验证机制。
3.4、实体报头
请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正文组成,但并不是说实体报头域和实体正文要在一起发送,可以只发送实体报头域。实体报头定义了关于实体正文和请求所标识的资源的元信息。 常用的实体报头如下:
-
Content-Encoding:Content-Encoding实体报头域被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding这样用于记录文档的压缩方法。Content-Encoding:gzip
-
Content-Language:Content-Language实体报头域描述了资源所用的自然语言。没有设置该域则认为实体内容将提供给所有的语言阅读者。Content-Language:da
-
Content-Length:Content-Length实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
-
Content-Type:Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。Content-Type:text/html;charset=ISO-8859-1、Content-Type:text/html;charset=GB2312
-
Last-Modified:Last-Modified实体报头域用于指示资源的最后修改日期和时间。
-
Expires:Expires实体报头域给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,我们可以使用Expires实体报头域指定页面过期的时间。Expires:Thu,15 Sep 2006 16:23:12 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。为了让浏览器不要缓存页面,我们也可以利用Expires实体报头域,设置为0,jsp中程序如下:response.setDateHeader(“Expires”,”0”);
4、HTTP请求方式:HttpURLConnection
前面介绍的都是概念性的东西,下面我们介绍Android中使用的网络通信有两种方式:Socket和HTTP,Socket我们后面再讲。HTTP有两种方式:HttpUrlConnection和HttpClient,虽然我们实际开发中很少使用这两种请求方法,使用别人封装好的网络请求框架:Volley、AndroidAsync-http、OkHttp等,虽然第三方框架很好用,但是还是需要学习一下基础的东西的,下面我们来学习一下HttpUrlConnection请求方式。
HttpUrlConnection是一种轻量级、多用途的客户端,可以适用于大多数的HTTP网络操作。下面我们通过例子体会一下HttpUrlConnection的使用吧:
HttpUrlConnection使用步骤:
-
1、创建一个URL对象,例如:URL url = new URL(www.hao123.com);
-
2、通过URL对象的openConnection( )方法获取HttpUrlConnection对象实例
-
3、设置请求方法:GET或者POST等
-
4、设置连接超时时间,或者设置一些其他的请求参数
-
5、对响应码进行判断,如果成功就调用getInputStream()方法获得服务器返回的输入流,读取输入流,获得响应的内容;如果失败就重新请求或者执行其它操作
-
6、调用disConnect()方法断开连接
下面我们实现一个简单的GET请求例子:
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center"
android:orientation="horizontal">
<Button
android:id="@+id/btn_req_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求图片"/>
<Button
android:id="@+id/btn_req_web"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求网页"/>
<Button
android:id="@+id/btn_req_html"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求HTML源码"/>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_req_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
<ScrollView
android:id="@+id/sv_req_html"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:id="@+id/tv_req_html"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</ScrollView>
<WebView
android:id="@+id/wv_req_web"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
</FrameLayout>
</LinearLayout>
Activity代码:
package com.example.datasave;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by Devin on 2016/7/22.
*/
public class HUConnActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn_req_image;
private Button btn_req_web;
private Button btn_req_html;
private ImageView iv_req_image;
private TextView tv_req_html;
private ScrollView sv_req_html;
private WebView wv_req_web;
private static String URL_HTML = "https://www.baidu.com/";
private static String URL_IMAGE = "https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png";
private static final int HANDLER_IMAGE = 1001;
private static final int HANDLER_HTML = 1002;
private static final int HANDLER_WEB = 1003;
private static final int HANDLER_LOST = 1004;
private Bitmap mBitmap;
private String mResult;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HANDLER_IMAGE:
hideAllView();
iv_req_image.setVisibility(View.VISIBLE);
iv_req_image.setImageBitmap(mBitmap);
ToastUtils.showToast(getApplicationContext(), "图片加载完成");
break;
case HANDLER_HTML:
hideAllView();
sv_req_html.setVisibility(View.VISIBLE);
tv_req_html.setText(mResult);
ToastUtils.showToast(getApplicationContext(), "HTML源码加载完成");
break;
case HANDLER_WEB:
hideAllView();
wv_req_web.setVisibility(View.VISIBLE);
wv_req_web.loadDataWithBaseURL("", mResult, "text/html", "UTF-8", "");
ToastUtils.showToast(getApplicationContext(), "网页加载完成");
break;
case HANDLER_LOST:
ToastUtils.showToast(getApplicationContext(), "请求失败");
break;
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_huc);
btn_req_image = (Button) findViewById(R.id.btn_req_image);
btn_req_web = (Button) findViewById(R.id.btn_req_web);
btn_req_html = (Button) findViewById(R.id.btn_req_html);
iv_req_image = (ImageView) findViewById(R.id.iv_req_image);
tv_req_html = (TextView) findViewById(R.id.tv_req_html);
sv_req_html = (ScrollView) findViewById(R.id.sv_req_html);
wv_req_web = (WebView) findViewById(R.id.wv_req_web);
btn_req_image.setOnClickListener(this);
btn_req_html.setOnClickListener(this);
btn_req_web.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_req_image:
new Thread(new Runnable() {
@Override
public void run() {
try {
mBitmap = getImage(URL_IMAGE);
mHandler.sendEmptyMessage(HANDLER_IMAGE);
} catch (Exception e) {
e.printStackTrace();
mHandler.sendEmptyMessage(HANDLER_LOST);
}
}
}).start();
break;
case R.id.btn_req_html:
new Thread(new Runnable() {
@Override
public void run() {
try {
mResult = getHtml(URL_HTML);
mHandler.sendEmptyMessage(HANDLER_HTML);
} catch (Exception e) {
e.printStackTrace();
mHandler.sendEmptyMessage(HANDLER_LOST);
}
}
}).start();
break;
case R.id.btn_req_web:
if (mResult == null || mResult.equals("")) {
mHandler.sendEmptyMessage(HANDLER_HTML);
} else {
mHandler.sendEmptyMessage(HANDLER_WEB);
}
break;
}
}
/**
* 请求图片
*
* @param path
* @return
* @throws Exception
*/
private static Bitmap getImage(String path) throws Exception {
URL url = new URL(path);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(5000);
int resCode = httpURLConnection.getResponseCode();
if (resCode != 200) {
throw new RuntimeException("请求失败");
}
InputStream inputStream = httpURLConnection.getInputStream();
byte[] bytes = inputStream2Byte(inputStream);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
return bitmap;
}
/**
* 获取网页代码
*
* @param path
* @return
* @throws Exception
*/
private static String getHtml(String path) throws Exception {
URL url = new URL(path);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(5000);
int resCode = httpURLConnection.getResponseCode();
if (resCode != 200) {
throw new RuntimeException("请求失败");
}
InputStream inputStream = httpURLConnection.getInputStream();
byte[] bytes = inputStream2Byte(inputStream);
String result = new String(bytes, "UTF-8");
return result;
}
private static byte[] inputStream2Byte(InputStream inputStream) throws Exception {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
inputStream.close();
return byteArrayOutputStream.toByteArray();
}
/**
* 隐藏所有的View
*/
private void hideAllView() {
if (iv_req_image != null) {
iv_req_image.setVisibility(View.INVISIBLE);
}
if (sv_req_html != null) {
sv_req_html.setVisibility(View.INVISIBLE);
}
if (wv_req_web != null) {
wv_req_web.setVisibility(View.INVISIBLE);
}
}
}
请求需要联网,所以需要添加联网的权限
<uses-permission android:name="android.permission.INTERNET"/>
实现的效果图:
使用HttpUrlConnection实现POST请求:
布局文件很简单就不贴代码了,下面是Activity的代码:
package com.example.datasave;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by Devin on 2016/7/22.
*/
public class HUCPostActivity extends AppCompatActivity {
private Button btn_req_post;
private EditText et_user_name;
private EditText et_user_pass;
private static String URL_POST = "http://192.168.0.101:8080/csdnserver/TestHttpServlet";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hupost);
btn_req_post = (Button) findViewById(R.id.btn_req_post);
et_user_name = (EditText) findViewById(R.id.et_user_name);
et_user_pass = (EditText) findViewById(R.id.et_user_pass);
btn_req_post.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final String username = et_user_name.getText().toString();
final String password = et_user_pass.getText().toString();
new Thread(new Runnable() {
@Override
public void run() {
try {
String result = login(username, password);
Message message = mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString("result", result);
message.setData(bundle);
mHandler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
});
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
String result = (String) bundle.get("result");
ToastUtils.showToast(getApplicationContext(), result);
}
};
private String login(String username, String passsword) throws Exception {
URL url = new URL(URL_POST);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setConnectTimeout(5000);
httpURLConnection.setReadTimeout(5000);
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setUseCaches(false);
String date = "username=" + username + "&password=" + passsword;
OutputStream outputStream = httpURLConnection.getOutputStream();
outputStream.write(date.getBytes("UTF-8"));
outputStream.flush();
int resCode = httpURLConnection.getResponseCode();
if (resCode == 200) {
InputStream inputStream = httpURLConnection.getInputStream();
ByteArrayOutputStream aos = new ByteArrayOutputStream();
byte[] bb = new byte[1024];
int len = 0;
while ((len = inputStream.read(bb)) != -1) {
aos.write(bb, 0, len);
}
inputStream.close();
aos.close();
return new String(aos.toByteArray());
}
return null;
}
}
实现效果图:
服务器端打印的数据
这样我们基本就能实现HttpUrlConnection的GET请求和POST请求,现在大多是使用这两种请求方式比较多。
5、HTTP请求方式:HttpClient
在Android新的版本中,已经将HttpClient请求方式删除了,不再使用这种请求方式了,所以就简单介绍一下这种请求方式好了,具体的代码实现就不做了。
HttpClient请求实现流程(步骤):
-
1、创建一个HttpClient对象的实例:HttpClient client=newDefaultHttpclient();
-
2、发送GET的请求的话就创建HttpGet对象实例,发送POST请求的话就创建HttpPost对象实例
-
3、设置请求参数
-
4、调用HttpClient的execute()方法发送请求
-
5、获取响应的HttpResponse,解析数据
一个完整的HttpClient请求的基本流程是这样的,注意,网络请求一定要在子线程里面,不能在UI线程,不然会报错。
下面是网上的请求核心代码:
GET请求的核心代码:
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("https://www.baidu.com/");
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = httpResponse.getEntity();
detail = EntityUtils.toString(entity, "utf-8");
}
POST请求的核心代码:
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", "123456"));
params.add(new BasicNameValuePair("password", "123456"));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params,"UTF-8");
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity entity2 = httpResponse.getEntity();
detail = EntityUtils.toString(entity2, "utf-8");
}
关于HTTP协议和Android中两种HTTP请求方法HttpUrlConnection和HttpClient就简单介绍到这里了,后面我们会介绍一些比较常用的网络请求框架。