Java socket模拟HTTP协议客户端之POST请求

相比于GET请求,POST报文多了如下几个要素:

1,Content-Length,这个是上送报文的长度,以字节为单位

2,Content-Type,这主要是涉及到报文的格式和字符集。

3,就是主报文

主类SimpleHttpPost:

package com.zws.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
 * 
 * @author wensh.zhu 2017-03-11
  请求报文格式:
	GET /greeting.do?name=jack HTTP/1.1\r\n
	Host: localhost:8011\r\n
	Connection: keep-alive\r\n
	Cache-Control: max-age=0\r\n
	Upgrade-Insecure-Requests: 1\r\n
	User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\r\n
	Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*此处为斜线(/)*;q=0.8\r\n
	Accept-Encoding: gzip, deflate, sdch, br\r\n
	Accept-Language: zh-CN,zh;q=0.8\r\n
	Content-Length: 14\r\n
	Content-Type, application/x-www-form-urlencoded;charset=UTF-8\r\n
	\r\n
	id=1&name=jack
   
  响应报文格式:
  一次性响应:
 	HTTP/1.1 200 OK\r\n
	Server: Apache-Coyote/1.1\r\n
	Set-Cookie: JSESSIONID=54B11BE01CD7983726618546CF4521E1; Path=/Newer/; HttpOnly\r\n
	Content-Type: text/html;charset=UTF-8\r\n
	Content-Length: 4\r\n						//报文正文长度
	Date: Sat, 11 Mar 2017 15:16:10 GMT\r\n
	\r\n										//报头结束
	abcd										//正文

      分块响应:
	HTTP/1.1 200 OK\r\n
	Content-Type: application/json;charset=UTF-8\r\n
	Transfer-Encoding: chunked\r\n						//表示分块响应
	Date: Sat, 11 Mar 2017 14:19:25 GMT\r\n
	\r\n     			//报头结束
	8\r\n				//十六进制长度
	abcdefgh\r\n		//正文 
	2\r\n
	ab\r\n
	0\r\n				//结束
 */
public class SimpleHttpPost {
	private int connectTimeout = 2000;	//链接超时时间
	private int readTimeout = 5000;		//读超时时间
	private String host;
	private int port = 80;
	private String resource = "/";
	private String reqLine;
	private String body;
	private Map<String, String> headers = new HashMap<String, String>();

	public SimpleHttpPost(String uri) {
		initRequestHeader();
		parseRequestLine(uri);
	}

	public SimpleHttpPost(String uri, int connectTimeout, int readTimeOut) {
		initRequestHeader();
		parseRequestLine(uri);
		this.connectTimeout = connectTimeout;
		this.readTimeout = readTimeOut;
	}
	/**
	 * 解析出IP地址、端口以及请求资源
	 * @param uri
	 */
	private void parseRequestLine(String uri) {
		String url = uri;
		if (url == null) 
			throw new NullPointerException("uri can not be null");
		if (!url.startsWith("http"))
			url = "http://" + uri;
		String[] parts = url.split("//");
		if (parts.length >= 2) {
			String mainPart = parts[1];
			int ipFlag = mainPart.indexOf("/");
			if (ipFlag != -1) {
				String ipPart = mainPart.substring(0, ipFlag);
				resource = mainPart.substring(ipFlag);
				String[] ipParts = ipPart.split(":");
				if (ipParts.length > 1) {
					host = ipParts[0];
					String portStr = ipParts[1];
					if (portStr != null && portStr.length() > 0)
						port = Integer.parseInt(portStr);
				} else {
					host = ipPart;
				}
			} else {
				host = mainPart;
			}
		} else {
			throw new IllegalArgumentException("非法的uri");
		}
		String hostVal = host;
		if (port != 80) hostVal += ":" + port;
		headers.put("Host", hostVal);

		reqLine = "POST " + resource + " HTTP/1.1\r\n";
	}
	/**
	 * 初始化请求头
	 */
	private void initRequestHeader() {
		headers.put("Connection", "keep-alive");
		headers.put("Upgrade-Insecure-Requests", "1");
		headers.put("User-Agent", "Java client");
		headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
		headers.put("Accept-Encoding", "gzip");
		headers.put("Accept-Language", "zh-CN,zh");
		headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
	}

	public void setHeader(String key, String value) {
		headers.put(key, value);
	}

	private void concatParam(Map<String, String> parameters){
		if (parameters == null || parameters.isEmpty()) return;

		String params = "";
		Iterator<String> itor = parameters.keySet().iterator();
		while (itor.hasNext()) {
			String key = itor.next();
			String val = parameters.get(key);
			params += ("&" + key + "=" + val);
		}
		body = params.replaceFirst("&", "");
	}

	public RespMsg req(Map<String, String> parameters) {
		concatParam(parameters);
		int contentLen = 0;
		if (body != null)
			contentLen = body.getBytes().length;
		this.headers.put("Content-Length", String.valueOf(contentLen));
		RespMsg msg = null;
		Socket socket = null;
		OutputStream out = null;
		InputStream in = null;
		try {
			SocketAddress endpoint = new InetSocketAddress(host, port);
			socket = new Socket();
			socket.connect(endpoint, connectTimeout);
			socket.setSoTimeout(readTimeout);

			out = socket.getOutputStream();
			write(out);

			in = socket.getInputStream();
			msg = read(in);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
				if (socket != null) 
					socket.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}

		}
		return msg;
	}

	private void write(OutputStream out) throws IOException {
		String reqBody = reqLine;
		Iterator<String> itor = headers.keySet().iterator();
		while (itor.hasNext()) {
			String key = itor.next();
			String val = headers.get(key);
			String header = key + ":" + val + "\r\n";
			reqBody += header;
		}

		reqBody += "\r\n";
		reqBody += body;
		out.write(reqBody.getBytes("UTF-8"));
	}

	private RespMsg read(InputStream in) throws IOException {
		RespMsg respMsg = new RespMsg();
		byte[] heads = HttpStreamReader.readHeaders(in);
		String headStr = new String(heads);
		String[] lines = headStr.split("\r\n");
		RespHeader resp = new RespHeader();
		if (lines.length > 0) 
			resp.setRespLine(lines[0]);

		for (int i = 1; i < lines.length; i++) 
			resp.addHeader(lines[i]);

		String body = null;
		if (resp.isChunked()) {
			body = readChunked(in);
		} else {
			int bodyLen = resp.getContentLenth();
			byte[] bodyBts = new byte[bodyLen];
			in.read(bodyBts);

			body = new String(bodyBts, "UTF-8");
		}
		respMsg.setRespBody(body);
		String respLine = resp.getRespLine();
		respMsg.setRespCodeMsg(respLine);

		return respMsg;
	}
	/**
	 * 分块读取
	 * @param in
	 * @return
	 * @throws IOException
	 */
	private static String readChunked(InputStream in) throws IOException {
		String content = "";
		String lenStr = "0";
		while (!(lenStr = new String(HttpStreamReader.readLine(in))).equals("0")) {
			int len = Integer.valueOf(lenStr.toUpperCase(),16);//长度16进制表示
			byte[] cnt = new byte[len];
			in.read(cnt);
			content += new String(cnt, "UTF-8");
			in.skip(2);
		}

		return content;
	}

}

测试类Example:

package com.zws.http;

import java.util.HashMap;
import java.util.Map;

public class Example {

	public static void main(String[] args) {
		post();
	}

	public static void post() {
		String uri = "http://localhost:8080/Newer/server.action";

		Map<String, String> params = new HashMap<String, String>();
		params.put("id", "123");
		params.put("name", "张三");

		SimpleHttpPost post = new SimpleHttpPost(uri);
		RespMsg msg = post.req(params);

		String respCodeMsg = msg.getRespCodeMsg();
		String respBody = msg.getRespBody();

		System.out.println(respCodeMsg);
		System.out.println(respBody);
	}
}
时间: 2024-10-14 11:18:18

Java socket模拟HTTP协议客户端之POST请求的相关文章

Java socket模拟聊天程序

 根据TCP/IP协议,通过socket实现网络聊天,分为服务器端和客户端,一下是参考程序. 服务器端程序: package com.michael.contact; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.ne

java socket 模拟im 即时通讯

自己想了一下怎么实现,就写了,没有深究是否合理.更多处理没有写下去,例如收件人不在线,应该保存在数据库,等下一次连接的时候刷新map,再把数据发送过去,图片发送也没有做,也没有用json格式 socket很奇怪,我用客户端连接上了服务器,没有发送消息的情况下,断开电脑网络,是不会出现问题,然后在把电脑网络连接上,通讯依然正常,正常断开也不出问题,但是用idea直接按stop键,那么服务端就会出问题了,读取事件会一直为true,造成死循环,消耗CPU,所以必须要判断一下客户端连接是否断开了 只需要

java socket模拟http请求

我们模拟SSLSocket连接,请求博客园首页,并打印响应消息.代码引用来自<Java网络编程精解>作者:孙卫琴 写这篇博客为了说明模拟过程中出现的一些问题,模拟时请先在浏览器访问目标路径,F12查看网络,查看原始的网络请求头. 注意: 1.HTTP请求报文包含请求行.请求头部.空行.请求包体4个部分组成. 2.模拟请求头部时Accept-Encoding不要使用压缩,否则响应结果会出现乱码 3.请求头部结束使用回车换行符结束 代码如下: package com.beluga.hello.ht

java socket 单服务器多客户端实时通信

想用JAVA做一个服务器,请问怎么利用TCP和线程,实现多个客户端同时在线,能与服务器进行交互? 服务器监听端口 做个无限循环 接到一个连接就创建一个通道线程,并将通道线程存储到一个list集合中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 5

【学习笔记】Python网络编程(三)利用socket模拟ssh协议

上代码,server端: import socket,os s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) host = '' port = 1051 s.bind((host,port)) s.listen(4) while 1:     conn,addr = s.accept()     while 1:         data = conn.recv(1024)         if not data:break        

【学习笔记】Python网络编程(四)完善socket模拟ssh协议

server端代码: import socket,commands host =  '' port = 1053 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s.bind((host,port)) s.listen(1) while 1:     conn,addr = s.accept()     while 1:         data = conn.recv(1024)         cc,bb = commands.get

【转】使用java程序模拟页面发送http的post请求

在web应用程序中,一般都是通过页面发送http的post请求,但也可以使用java程序来模拟页面发送请求,代码如下: [java] view plaincopy import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.

http协议客户端向服务器端请求时一般需要发送的内容

out.println("GET /shopping/index.html HTTP/1.1");//请求行 包括请求方式,文件路径, http协议版本(必写)请求头.... out.println("Aceept: */*");//客户端能够处理的文件类型(不是必须) out.println("Host: 192.168.1.111:8080");//客户端要访问的主机及服务器的端口(必写),否则会出现400(请求错误) out.println

java web基础2HTTP协议知识点总结

一.HTTP协议基础 1.定义:HTTP是基于TCP连接的浏览器与服务器通信协议.(即传输层先用TCP三次握手建立连接,进而HTTP通信) 2.连接原理:先进行TCP建立端到端连接,然后发送和接受HTTP报文. TCP(Socket)是端到端的连接,通过IP地址和端口号用于定位网络上两台主机的具体运行程序.所以HTTP连接会先启动TCP连接来建立与服务器软件的连接,然后发送和接受HTTP报文内容.所以当运行抓包器,打开网页时,会看到一个TCP连接和HTTP连接.在用HTTP 1.0版本时,每打开