Http 请求及相应
请求包结构

示例:
POST /meme.php/home/user/login HTTP/1.1
Host: 114.215.86.90
Cache-Control: no-cache
Postman-Token: bd243d6b-da03-902f-0a2c-8e9377f6f6ed
Content-Type: application/x-www-form-urlencoded
tel=13637829200&password=123456
响应包结构

示例:
HTTP/1.1 200 OK
Date: Sat, 02 Jan 2016 13:20:55 GMT
Server: Apache/2.4.6 (CentOS) PHP/5.6.14
X-Powered-By: PHP/5.6.14
Content-Length: 78
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: application/json; charset=utf-8
{"status":202,"info":"\u6b64\u7528\u6237\u4e0d\u5b58\u5728\uff01","data":null}
Http 请求方式
-
GET
请求指定url的数据,请求体为空(例如打开网页)。 -
POST
请求指定url的数据,同时传递参数(在请求体中)。 -
HEAD
类似于get请求,只不过返回的响应体为空,用于获取响应头。 -
PUT
从客户端向服务器传送的数据取代指定的文档的内容。 -
DELETE
请求服务器删除指定的页面。 -
CONNECT
HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 -
OPTIONS
允许客户端查看服务器的性能。 -
TRACE
回显服务器收到的请求,主要用于测试或诊断。
常用请求方式 GET 和 POST
GET & POST
-
GET 通常是从服务器获取数据,POST 通常是香服务器传输数据。
-
GET 是把参数数据队列加到表单的 ACTION 属性所指的 URL 中,值和表单内各个字段一一对应,在 URL 中可以看到,实际上就是 URL 拼接方式。POST 是通过 HTTP POST 机制,将表单内各个字段与其内容放置在 HTML HEADER 中一起传送到 ACTION 属性所指向的 URL 中。
-
服务器通过 Request.QueryString 获取 GET 变量值,通过 Request.Form 获取 POST 提交的值。
-
GET 提交的数据量小,不能大于 1kb。POST 提交的数据量较大,一般被默认为不受限制,但理论上,IIS4 中最大量为 80KB,IIS5 中为 100KB。
-
GET 安全性低,POST 安全性高。
使用 HttpURLConnection 发送 HTTP 请求
以前,Android 上发送 HTTP 请求有两种方式,HttpURLConnection 和 HttpClient。不过由于 HttpClient 存在 API 数量众多,维护困难等缺点,Android 大版本6.0之后,HttpClient 就被完全移除了。现在官方建议使用 HttpURLConnection。
流程
- 获取 HttpURLConnection 实例
new 一个 URL 对象,并传入要访问的地址,然后调用一下 HttpURLConnection 的 openConnection() 方法即可。
URL lURL = new URL("https://www.baidu.com/");//请求 url
lHttpURLConnection = (HttpURLConnection) lURL.openConnection();
- 设置 HTTP 请求方法
lHttpURLConnection.setRequestMethod("GET");//请求方法, HttpURLConnection 默认请求方式即为 GET 请求,所以本句可省略
- 接下来可自由定制
如连接超时、读取超时的设置,或服务器希望得到的一些消息头等
lHttpURLConnection.setConnectTimeout(8000);//与服务器建立连接超时设置
lHttpURLConnection.setReadTimeout(8000);//与服务器传递数据的超时设置
- 然后调用 getInstreamInput() 方法获取服务器返回的输入流
对返回的输入流进行读取
InputStream lInputStream = lHttpURLConnection.getInputStream();
- 关闭 HTTP 连接
lHttpURLConnection.disconnect();
示例
- 布局
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ginkwang.networktest">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
- 逻辑
public class MainActivity extends AppCompatActivity {
private Button mBtnSendRequest;
private TextView mTvResponseTxt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mBtnSendRequest = (Button) findViewById(R.id.btn_send_request);
mBtnSendRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendRequestWithHttpURLConnection();
}
});
mTvResponseTxt = (TextView) findViewById(R.id.tv_response_txt);
}
private void sendRequestWithHttpURLConnection() {
//开启线程发起请求
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection lHttpURLConnection = null;
BufferedReader lBufferedReader = null;
try {
URL lURL = new URL("https://www.baidu.com/");//请求 url
lHttpURLConnection = (HttpURLConnection) lURL.openConnection();
lHttpURLConnection.setRequestMethod("GET");//请求方法,HttpURLConnection 默认请求方式即为 GET 请求,所以本句可省略
lHttpURLConnection.setConnectTimeout(8000);//与服务器建立连接超时设置
lHttpURLConnection.setReadTimeout(8000);//与服务器传递数据的超时设置
InputStream lInputStream = lHttpURLConnection.getInputStream();
//读取获取到的输入流
lBufferedReader = new BufferedReader(new InputStreamReader(lInputStream));
StringBuilder lStringBuilder = new StringBuilder();
String line = "";
while ((line = lBufferedReader.readLine()) != null) {
lStringBuilder.append(line);
}
showResponse(lStringBuilder.toString());
} catch (Exception pE) {
pE.printStackTrace();
} finally {
if (lBufferedReader != null) {
try {
lBufferedReader.close();
} catch (IOException pE) {
pE.printStackTrace();
}
}
if (lHttpURLConnection != null) {
lHttpURLConnection.disconnect();
}
}
}
}).start();
}
private void showResponse(final String result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
// 线程切回到主线程,进行 UI 更新操作
mTvResponseTxt.setText(result);
}
});
}
}
- 权限声明
<uses-permission android:name="android.permission.INTERNET"/>
- 效果

HttpURLConnection 参数详解
-
setRequestMethod
设置请求方法 -
setDoOutPut
设置是否向 HttpURLConnection 输出,Get 请求用不到 lHttpURLConnection.getOutputStream(),因为参数直接追加在地址后面,因此默认是false。而 Post 请求参数要放在 http 正文内,因此需要设为 true。 -
setDoInPut
设置是否从 HttpUrlConnection 读入,默认情况下是 true;指示应用程序要从 URL 连接读取数据。 -
setConnectTimeout
与服务器建立连接超时设置 -
setReadTimeOut
与服务器传递数据的超时设置 -
setInstanceFollowRedirects
设置本次连接是否自动重定向 -
setRequestProperty
设置头信息,如格式等,一般不设置,有默认设置 -
connect
不必要调用 connect 方法(调用也无妨),实际上只是建立了一个与服务器的 tcp 连接,并没有实际发送 http 请求。无论是 post 还是 get,http请求实际上直到HttpURLConnection 的 getInputStream() 这个函数里面才正式发送出去。
基于 HttpURLConnection 的 HTTP 请求封装
直接上代码
/**
* 网络请求类
* Created by Wang-gk on 2017/5/2.
*/
public class NetworkHandler {
private static final String TAG = "NetworkHandler";
private static final int TIMEOUT = 15000;//超时设置
/**
* 请求参数格式转换
* @param pMap 请求参数
* @return
*/
private static String prepareParam(Map<String, Object> pMap) {
StringBuffer lStringBuffer = new StringBuffer();
if (pMap.isEmpty()) {
return "";
} else {
for (String key : pMap.keySet()) {
String value = (String) pMap.get(key);
if (lStringBuffer.length() < 1) {
lStringBuffer.append(key).append("=").append(value);
} else {
lStringBuffer.append("&").append(key).append("=").append(value);
}
}
}
return lStringBuffer.toString();
}
/**
* Get 请求
* @param pUrl 请求地址
* @param pParamMap 请求参数
* @param pListener 接口回调
*/
public static void doGet(String pUrl, Map<String, Object> pParamMap, NetworkCallbackListener pListener) {
HttpURLConnection lHttpURLConnection = null;
BufferedReader lBufferedReader = null;
if (pParamMap != null && pParamMap.size() > 0) {
pUrl += prepareParam(pParamMap);
}
try {
URL lURL = new URL(pUrl);
lHttpURLConnection = (HttpURLConnection) lURL.openConnection();//初始化 HttpURLConnection
lHttpURLConnection.setRequestMethod("GET");//设置请求方法
lHttpURLConnection.setDoOutput(false);//设置是否向connection输出, get请求用不到 lHttpURLConnection.getOutputStream(),因为参数直接追加在地址后面,因此默认是false
lHttpURLConnection.setDoInput(true);// 设置是否从 HttpUrlConnection 读入,默认情况下是 true;指示应用程序要从 URL 连接读取数据。
lHttpURLConnection.setConnectTimeout(TIMEOUT);//与服务器建立连接超时设置
lHttpURLConnection.setReadTimeout(TIMEOUT);//与服务器传递数据的超时设置
lHttpURLConnection.setInstanceFollowRedirects(true);//设置本次连接是否自动重定向
lHttpURLConnection.setRequestProperty("Content-Type","text/html; charset=UTF-8");//设置头信息,如格式等,一般不设置,有默认设置
lHttpURLConnection.connect();//不必要调用connect方法(调用也无妨),实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
InputStream lInputStream = lHttpURLConnection.getInputStream();
//读取获取到的输入流
lBufferedReader = new BufferedReader(new InputStreamReader(lInputStream));
StringBuilder lStringBuilder = new StringBuilder();
String line = "";
while ((line = lBufferedReader.readLine()) != null) {
lStringBuilder.append(line);
}
Log.i(TAG, "doGet: output <<< " + lStringBuilder.toString());
if (pListener != null) {
pListener.onFinish(lStringBuilder.toString());
}
} catch (Exception pE) {
if (pListener != null) {
pListener.onError(pE);
}
} finally {
if (lHttpURLConnection != null) {
lHttpURLConnection.disconnect();
}
if (lBufferedReader != null) {
try {
lBufferedReader.close();
} catch (IOException pE) {
pE.printStackTrace();
}
}
}
}
/**
* Post 请求
* @param pUrl 请求地址
* @param pParamMap 请求参数
* @param pListener 接口回调
*/
public static void doPost(String pUrl, Map<String, Object> pParamMap, NetworkCallbackListener pListener) {
HttpURLConnection lHttpURLConnection = null;
BufferedReader lBufferedReader = null;
try {
URL lURL = new URL(pUrl);
lHttpURLConnection = (HttpURLConnection) lURL.openConnection();//初始化 HttpURLConnection
lHttpURLConnection.setRequestMethod("POST");//设置请求方法
lHttpURLConnection.setDoOutput(true);//设置是否向connection输出,因为这个是 post 请求,参数要放在 http 正文内,因此需要设为 true
lHttpURLConnection.setDoInput(true);// 设置是否从 HttpUrlConnection 读入,默认情况下是 true;指示应用程序要从 URL 连接读取数据。
lHttpURLConnection.setConnectTimeout(TIMEOUT);//与服务器建立连接超时设置
lHttpURLConnection.setReadTimeout(TIMEOUT);//与服务器传递数据的超时设置
lHttpURLConnection.setInstanceFollowRedirects(true);//设置本次连接是否自动重定向
lHttpURLConnection.setRequestProperty("Content-Type","text/html; charset=UTF-8");//设置头信息,如格式等,一般不设置,有默认设置
lHttpURLConnection.connect();//不必要调用connect方法(调用也无妨),实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。
InputStream lInputStream = lHttpURLConnection.getInputStream();
//读取获取到的输入流
lBufferedReader = new BufferedReader(new InputStreamReader(lInputStream));
StringBuilder lStringBuilder = new StringBuilder();
String line = "";
while ((line = lBufferedReader.readLine()) != null) {
lStringBuilder.append(line);
}
Log.i(TAG, "doPost: output <<< " + lStringBuilder.toString());
if (pListener != null) {
pListener.onFinish(lStringBuilder.toString());
}
} catch (Exception pE) {
if (pListener != null) {
pListener.onError(pE);
}
} finally {
if (lHttpURLConnection != null) {
lHttpURLConnection.disconnect();
}
if (lBufferedReader != null) {
try {
lBufferedReader.close();
} catch (IOException pE) {
pE.printStackTrace();
}
}
}
}
}
其中,网络请求的回调操作也封装在内。主要就是交易完成 onFinish() 和 onError() 两个回调方法,在接口回调类 NetworkCallbackListener 中定义
/**
* 网络处理接口
* Created by Wang-gk on 2017/5/4.
*/
public interface NetworkCallbackListener {
void onFinish(String pResponse);
void onError(Exception pE);
}
参考
-
郭霖 《第一行代码》
网友评论