之前的Android开发中一直都有用到http+json的方式来与服务器做通信(相信http应该也是目前大多数app开发所使用的协议),基本上就是用HttpClient或者是HttpURLConnection并借用网上的代码改改用在项目中,却连HTTP的根本都没有一个认识,也发现自己一直颓废了好长时间没什么进步了,然后想用okhttp对目前项目做些改进,发现还是得从了解HTTP结构开始。废话多了,进入正题,若有不正确的地方欢迎指正。
HTTP介绍
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。它是一个客户端和服务器端请求和应答的标准,并且它是一个无状态协议,同一个客户端的这次请求和上次请求是没有对应关系,对http服务器来说,它并不知道这两个请求来自同一个客户端。 为了解决这个问题, Web程序引入了Cookie机制来维护状态,这也是Session保持所要涉及到的一个内容。
报文结构
Request
一个完整的HTTP请求由四个部分组成:请求行、消息头、一个空行和请求正文。
请求行
请求行由三个标记组成:请求方法、请求 URI 和 HTTP 版本,它们用空格分隔。
例如:
GET /index.html HTTP/1.1
消息头
消息头是一系列的Key/Value对组成,每个K/V一行,中间用冒号(:)分隔。这部分不展开详细介绍,见HTTP协议header标头详解
请求正文
HTTP 消息的消息体(并不要求必须存在,如GET请求就没有消息体),用于携带与请求相关联的数据,例如可以存一些请求需要的参数等。由消息头中的 Content-Length 或 Transfer-Encoding 来指示。消息头里的 Content-Type 说明了数据的传输类型。
Response
HTTP响应也由四个部分组成,分别是:状态行、消息头、空行和响应正文。
状态行
状态行也由三部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔。具体状态码见百度百科Http状态码
例如:
HTTP/1.1 200 OK
消息头
同请求消息头
响应正文
同请求正文
Content-Type
Content-Type是消息头中最有用处的一个头域,用于定义HTTP报文正文部分内容的类型和编码,Content-Type使用的是 “主类型/子类型; 额外参数” ( [type]/[subtype]; parameter )的数值格式。详细类型见Content-Type对照表。
主类型
以下是经常见到的几种主类型:
1.text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的; 默认是text/plain;
2.multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据; 默认是multipart/form-data;
3.application:用于传输应用程序数据或者二进制数据; 默认是application/octet-stream;
4.message:用于包装一个E-mail消息;
5.image:用于传输静态图片数据;
6.audio:用于传输音频或者音声数据;
7.video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。
子类型
用于指定”主类型”的详细形式。 其中以x-开头表示该类别尚未标准化 。当客户端不能确定“子类型”时,会根据“主类型”来获取默认的子类型。
额外参数
用于指定请求/响应内容的字符编码格式。例如text/html;charset=utf-8;
文件上传
大多数的时候我们要向服务器提交的东西主要是以直接的文本(K/V数据)或是Json为主,我们只要通过指定Content-Type为application/x-www-form-urlencoded(K/V结构数据时,数据将会通过UrlEncoded编码方式提交给服务器)或者是application/json即可。但在需要文件上传时,我们必须用multipart/form-data方式将数据POST给服务器。
multipart/form-data类型有个必须的额外参数boundary,该参数作为占位符用于将后续的正文内容分隔。为了避免和正常文本重复了,尽量要使用复杂无序一点的内容作为boundary的值,如:——————–56423498738365,服务端收到客户端提交的报文正文时,会用–${boundary}(即两个横杠后加上boundary的值)来作为正文内容的分隔符。以下为一个典型的请求内容:
----------------------56423498738365
Content-Disposition: form-data; name="Filename"
HTTP.pdf
----------------------56423498738365
Content-Disposition: form-data; name="file000"; filename="HTTP协议详解.pdf"
Content-Type: application/octet-stream
%PDF-1.5
file content
%%EOF
----------------------56423498738365
Content-Disposition: form-data; name="Upload"
Submit Query
----------------------56423498738365--
OKHTTP
okhttp最为Android上一个很好的网络通信解决方案库,它为我们做了很多的工作,这里简要介绍下它的使用。
gradle:
compile 'com.squareup.okhttp3:okhttp:3.2.0'
以上面的post请求为例,主要代码如下:
OKHttpClient client = new OKHttpClient();
try{
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
//添加非文件参数
builder.addFormDataPart("Filename", "HTTP.pdf");
builder.addFormDataPart("Upload", "Submit Query");
//添加文件
File file = new File(sFilePath);
builder.addFormDataPart("file000", "HTTP协议详解.pdf",RequestBody.create(MediaType.parse("application/octet-stream"), file));
Request request = Request.Builder().url(sUrl).post(builder.build()).build();
} catch (Exception e) {
e.printStackTrace();
}
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败处理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//成功交互处理
}
});