1-http 数据结构
![](https://img.haomeiwen.com/i17969152/b59313247c9f327f.png)
http 请求格式:(请求与响应有细微的差别)
![](https://img.haomeiwen.com/i17969152/4527d7921f67efc1.png)
http 响应格式
![](https://img.haomeiwen.com/i17969152/fdad6352d03232f7.png)
抓取包:
![](https://img.haomeiwen.com/i17969152/9204a84a5f33dc19.png)
2-http 参数说明
查找某个资源
URL:http://host[":"port][abs_path]
HTTP协议的方法有:
- GET: 请求获取Request-URI所标识的资源
- POST: 在Request-URI所标识的资源后增加新的数据
- HEAD: 请求获取由Request-URI所标识的资源的响应消息报头
- PUT: 请求服务器存储或修改一个资源,并用Request-URI作为其标识
- DELETE: 请求服务器删除Request-URI所标识的资源
- TRACE: 请求服务器回送收到的请求信息,主要用于测试或诊断
- CONNECT: 保留将来使用
- OPTIONS: 请求查询服务器的性能,或者查询与资源相关的选项和需求
http 消息包头【头key】
![](https://img.haomeiwen.com/i17969152/d396ff29fdb9ed38.png)
![](https://img.haomeiwen.com/i17969152/c9bd9b2bfb930c66.png)
![](https://img.haomeiwen.com/i17969152/a447ab9d183c6ccf.png)
![](https://img.haomeiwen.com/i17969152/9487186fe86f76d4.png)
状态行:
由3部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔
状态码:为3位数字
200-299的状态码表示成功
300-399的状态码指资源重定向
400-499的状态码指客户端请求出错
500-599的状态码指服务端出错(HTTP/1.1向协议中引入了信息性状态码,范围为100-199)
常见的:
200:响应成功
302:重定向跳转,跳转地址通过响应头中的Location属性指定
400:客户端请求有语法错误,参数错误,不能被服务器识别
403:服务器接收到请求,但是拒绝提供服务(认证失败)
404:请求资源不存在
500:服务器内部错误
3-http简单使用例子(okhttp vs 自己写)
HTTP的GET请求 [okhttp]
//1,创建okHttpClient对象
OkHttpClient mOkHttpClient = new OkHttpClient();
//2,创建一个Request
final Request request = new Request.Builder()
.url("https://www.baidu.com")
.build();
//3,新建一个call对象
Call call = mOkHttpClient.newCall(request);
//4,请求加入调度,这里是异步Get请求回调
call.enqueue(new Callback()
{
@Override
public void onFailure(Request request, IOException e)
{
}
@Override
public void onResponse(final Response response) throws IOException
{
//String htmlStr = response.body().string();
}
});
不使用第三方库 http 方法
server 与client 都是在android java 实现,举例调用了Socket.java的接口
libcore/ojluni/src/main/java/java/net/Socket.java
server 端
- 第一步,启动服务端,监听本机 IP 和指定端口的客户端连接
ServerSocket server = new ServerSocket();
// 要监听的IP和端口
SocketAddress address = new InetSocketAddress("192.168.1.111", 8888)
server.bind(address);
while (true) {
Socket socket = server.accept();
... // 读取请求,发送响应
}
- 第二步,分发客户端请求,因为会有很多客户端来连接服务端,因此若在同一个线程内处理请求,服务端会忙不过来,我们启动一个新线程来处理请求:
public class RequestHandler extends Thread {
private Socket mSocket;
public RequestHandler(Socket mSocket) {
this.mSocket = mSocket;
}
@Override
public void run() {
... // 读取请求,发送响应
}
}
优化监听:
while (true) {
Socket socket = server.accept();
System.out.println("---->>>> 发现客户端请求 <<<<----");
RequestHandler handler = new RequestHandler(socket);
handler.start();
}
- 第三步,简单的读取请求并打印请求数据&响应
/**
* 读取请求。
*/
private void readRequest(Socket socket) throws IOException {
InputStream is = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len;
while ((len = is.read(buffer)) > 0) {
bos.write(buffer, 0, len);
if (len < 2048) break;
}
System.out.println(new String(bos.toByteArray()));
}
--------------------------------------------------------------
/**
* 发送响应。
*/
private void sendResponse(Socket socket, byte[] data) throws IOException {
OutputStream os = socket.getOutputStream();
// 发送响应头
PrintStream print = new PrintStream(os);
print.println("HTTP/1.1 200 Beautiful");
print.println("Server: HttpServer/1.0");
print.println("Content-Length: " + data.length);
print.println("Content-Type: text/plain; charset=utf-8");
// 发送响应头和响应数据之间的换行
print.println();
// 发送响应数据
print.write(data);
os.flush();
}
上面run方法的实现:
public class RequestHandler extends Thread {
private static final Charset UTF8 = Charset.forName("utf-8");
private Socket mSocket;
public RequestHandler(Socket mSocket) {
this.mSocket = mSocket;
}
@Override
public void run() {
readRequest(mSocket);
String data = null;
try {
// 相当于服务端 HTTP API 处理业务,从数据库查数据等
data = "test response";
} catch(Exception e) {
data = "test response two";
}
sendResponse(mSocket, data.getByte(UTF8));
// 关闭Socket连接
mSocket.close();
}
}
client端
- 第一步,使用 Socket 建立和服务端的连接
// 要连接的主机域名和端口
InetSocketAddress address = new InetSocketAddress("192.168.1.111", 8888);
// 建立连接
Socket socket = new Socket();
socket.setSoTimeout(10 * 1000);
socket.connect(address, 10 * 1000);
- 第二步,按照格式发送请求头、换行和请求数据
// 发送请求头
PrintStream print = new PrintStream(socket.getOutputStream());
print.println("POST /abc/dev?ab=cdf HTTP/1.1");
print.println("Host: 192.168.1.111:8888");
print.println("User-Agent: HttpClient/1.0");
print.println("Content-Length: 15");
print.println("Accept: *");
// 发送请求头和请求数据之间的换行
print.println();
// 发送请求数据
print.println("恰同学少年");
- 第三步,简单的读取响应并打印响应数据
InputStream is = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len;
while ((len = is.read(buffer)) > 0) {
bos.write(buffer, 0, len);
if (len < 2048) break;
}
String body = new String(bos.toByteArray());
System.out.println(body);
REF:
https://www.jianshu.com/p/f3f228d3598c
https://yanzhenjie.blog.csdn.net/article/details/93098495
网友评论