http学习笔记(模拟http请求和响应过程)
2017-01-08 20:58
381 查看
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"); mOut 4000 putStream.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调用结束》》》"); }
}