HTTP请求消息
1、http请求报文格式解析:起始行+首部字段+主体
POST /api/feed/ HTTP/1.1 –起始行
Accept-Encoding: gzip –请求头
Content-Length: 225873
Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Host: www.myhost.com
Connection: Keep-Alive
(以下请求正文)
–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp –分隔符
Content-Disposition: form-data; name=”lng” –参数
Content-Type: text/plain; charset=UTF-8 –(说明是文本)
Content-Transfer-Encoding: 8bit
–空行
116.361545 参数值
–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=”lat”
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
39.979006
–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
Content-Disposition: form-data; name=”images”; filename=”/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg”
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
这里是图片的二进制数据
–OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp–
2、http响应报文格式解析
HTTP/1.1 200 OK
Date: Sun, 08 Jan 2017 08:24:23 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 908
resp{
errmsg=操作成功
errno=0
}
进入正题
1、模拟http服务器
package http;
import java.io.IOException;
import java.net.ServerSocket;
/**
* Created by 蓝师傅 on 2017/1/7.
*/
public class SimpleHttpServer extends Thread {
//端口号
public static final int HTTP_PORT = 8005;
ServerSocket mSocket = null;
public SimpleHttpServer(){
try {
mSocket = new ServerSocket(HTTP_PORT);
} catch (IOException e) {
throw new RuntimeException("服务器socket初始化失败");
}
}
@Override
public void run() {
//等待客户端连接
try {
while (true){
System.out.println("等待连接.....");
//这里会一直阻塞,知道有socket连接进来
//一旦客户端连接,拿到socket对象,交给DeliverThread 处理
new DeliverThread(mSocket.accept()).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
可以看到,SimpleHttpServer 是一个线程,run方法无限循环,被mSocket.accept() 阻塞,当有socket接入的时候会调用new DeliverThread(mSocket.accept()).start();,把请求交给DeliverThread 去处理,代码如下:
package http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* Created by 蓝师傅 on 2017/1/7.
* 处理请求的线程
*/
public class DeliverThread extends Thread {
Socket mClientSocket;
//输入流
BufferedReader mInputStream;
//输出流
PrintStream mOutputStream;
//请求方法
String httpMethod;
//子路径
String subPath;
//分隔符
String boundary;
//请求参数
Map<String,String> mParams = new HashMap<String,String>();
//是否已经解析完header
boolean isParseHeader;
public DeliverThread(Socket socket){
mClientSocket = socket;
}
@Override
public void run() {
/**
* 处理请求
*/
try {
//获取输入流
mInputStream = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
//获取输出流
mOutputStream = new PrintStream(mClientSocket.getOutputStream());
//解析请求
parseRequest();
//返回response
handleResponse();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
mInputStream.close();
mOutputStream.close();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 解析请求
*/
private void parseRequest() {
String line; //读一行数据
try {
int lineNum = 0;
while ((line = mInputStream.readLine())!= null){
//第一行是请求行
if(lineNum == 0){
parseRequestLine(line);
}
//是否是结束行
if(isEndLine(line)){
break;
}
//解析header参数
if(lineNum != 0 && !isParseHeader){
parseHeaders(line);
}
if(isParseHeader){
parseRequestParams(line);
}
lineNum ++;
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析请求正文参数
* @param line
*/
private void parseRequestParams(String line) throws IOException {
/**
*
-----------------------------7d77af5871cc4b 分隔符
Content-Disposition: form-data; name="last_server_md5" 参数名
空行
bdf244bde5deb41d0f24d5f2e13efcba 参数值
-----------------------------7d77af5871cc4b
Content-Disposition: form-data; name="t"
Q=u%3D%25PQ%250df551a583a87f4e9%26src%3D360chrome%26t%3D1
-----------------------------7d77af5871cc4b--
空行结束
*/
if(line.equals("--"+boundary)){ // 分隔符开始
String key = mInputStream.readLine(); //参数名
mInputStream.readLine(); //空行
String value = mInputStream.readLine(); //参数值
mParams.put(key,value);
System.out.println("解析参数,key="+key+",value="+value);
}
}
/**
* 解析请求头
* @param line
*/
private void parseHeaders(String line) {
//header以空行结束
if(line.equals("")){
//解析结束
isParseHeader = true;
System.out.println("解析到空行,解析header 结束》》》》");
return;
}else if(line.contains("boundary")){
boundary = parseSecondField(line);
System.out.println("解析到分隔符》》》》"+boundary);
}else{
//解析普通的header
parseHeaderParam(line);
}
}
/**
* 解析header参数
* @param line
*/
private void parseHeaderParam(String line) {
String[] keyValue = line.split(":");
mParams.put(keyValue[0].trim(),keyValue[1].trim());
System.out.println("解析header参数:key="+keyValue[0].trim()+",value = "+keyValue[1].trim());
}
/**
* 解析header 第二个参数,返回分隔符
* @param line
* @return
*/
private String parseSecondField(String line) {
//// TODO: 2017/1/8
//Content-Type: application/octet-stream
//Content-Type: application/octet-stream; boundary = abcdefg
String[] keyValue = line.split(";");
parseHeaderParam(keyValue[0]); // Content-Type: application/octet-stream
if(keyValue.length >1){
return keyValue[1].split("=")[1];
}
return "";
}
/**
* 是否是结束行
* @param line
* @return
*/
private boolean isEndLine(String line) {
return line.equals("--"+boundary+"--");
}
/**
* 解析请求行
* @param line
*/
private void parseRequestLine(String line) {
// 请求方法 空行 url 空行 http版本 回车符,换行符
String[] tempString = line.split(" ");
httpMethod = tempString[0]; //
subPath = tempString[1]; //
System.out.println("请求方法:"+tempString[0]);
System.out.println("子路径:"+tempString[1]);
System.out.println("http版本:"+tempString[2]);
}
/**
* 响应:返回结果
*/
private void handleResponse() {
try {
sleep(1000);
mOutputStream.println("HTTP/1.1 200 OK");
mOutputStream.println("Content-Type: application.json");
mOutputStream.println("");
mOutputStream.println("{\"stCode\":\"success\"}");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
然后呢,在main中调用 new SimpleHttpServer.start(); 即可启动服务器
看看客户端吧:
以post请求为例,客户端需要调用
HttpPost post = new HttpPost("127.0.0.1");
post.addParams("name", "lanshifu");
post.excute();
//发送post请求
HttpPost 的代码如下:
package http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Created by 蓝师傅 on 2017/1/8.
*/
public class HttpPost {
String url = "127.0.0.1";
//请求参数
Map<String,String> mParams = new HashMap<String,String>();
Socket mSocket;
public HttpPost(String url) {
this.url = url;
}
public void addParams(String key,String value){
mParams.put(key,value);
}
public void excute(){
try {
mSocket = new Socket(this.url,SimpleHttpServer.HTTP_PORT);
PrintStream outPutStream = new PrintStream(mSocket.getOutputStream());
BufferedReader inputStream = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
String boundray ="分割符";
writeHeader(boundray,outPutStream);
writeParams(boundray,outPutStream);
waitResponse(inputStream);
} catch (IOException e) {
e.printStackTrace();
//创建连接失败
}
}
/**
* 构造header
* @param boundray
* @param outPutStream
*/
private void writeHeader(String boundray, PrintStream outPutStream) {
outPutStream.println("POST /pro1/empManage1.0/login.php HTTP/1.1");
outPutStream.println("Accept-Encoding: gzip, deflate, sdch");
outPutStream.println("Accept-Language: zh-CN,zh;q=0.8");
outPutStream.println("Content-Type: application/octet-stream; boundray="+boundray);
outPutStream.println();
}
/**
* 构造请求正文参数
* @param boundray
* @param outPutStream
*/
private void writeParams(String boundray, PrintStream outPutStream) {
System.out.println("writeParams调用》》》");
Iterator<String> iterator = mParams.keySet().iterator();
while (iterator.hasNext()){
String paramName = iterator.next();
outPutStream.println("--"+boundray);
outPutStream.println("Content-Dusposition:from-data; name="+paramName);
outPutStream.println();
outPutStream.println(mParams.get(paramName));
System.out.println("writeParams,paramName=:"+mParams.get(paramName));
}
//结束符
outPutStream.println("--"+boundray+"--");
System.out.println("writeParams调用结束》》》");
}
/**
* 等待响应
* @param inputStream
*/
private void waitResponse(BufferedReader inputStream) {
System.out.println("waitResponse调用结束》》》");
}
}