HTTP协议可以说是WEB项目中最常用的协议了,项目开发中一般使用Httpclient进行HTTP接口的请求,Httpclient封装了HTTP协议的细节,如果不用Httpclient如何进行HTTP请求呢,下面是一个简单的实现HTTP协议的小程序:
主要类SimpleHttpGet:
package com.zws.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
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,p_w_picpath/webp,*此处为斜线(/)*;q=0.8\r\n
Accept-Encoding: gzip, deflate, sdch, br\r\n
Accept-Language: zh-CN,zh;q=0.8\r\n
\r\n
响应报文格式:
一次性响应:
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 SimpleHttpGet {
private int connectTimeout = 2000; //链接超时时间
private int readTimeout = 5000; //读超时时间
private String host;
private int port = 80;
private static String DEF_CHARSET = "UTF-8";
private String resourcePath = "/";//资源路径
private String reqLine;
private Map<String, String> headers = new HashMap<String, String>();
public SimpleHttpGet(String uri) {
initRequestHeader();
parseRequestLine(uri);
}
public SimpleHttpGet(String uri, int connectTimeout, int readTimeOut) {
initRequestHeader();
parseRequestLine(uri);
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeOut;
}
/**
* 解析出IP地址、端口以及请求资源
* @param uri
* @throws UnsupportedEncodingException
*/
private void parseRequestLine(String uri) {
String url = uri;
if (url == null || url.length() == 0)
throw new NullPointerException("uri can not be null");
if (!url.startsWith("http"))
url = "http://" + uri;
String[] parts = url.split("//");
String mainPart = parts[1];
int ipFlag = mainPart.indexOf("/");
if (ipFlag != -1) {
String ipPort = mainPart.substring(0, ipFlag);
String[] ipParts = ipPort.split(":");
if (ipParts.length > 1) {
host = ipParts[0];
String portStr = ipParts[1];
if (portStr != null && portStr.length() > 0)
port = Integer.parseInt(portStr);
} else {
host = ipPort;
}
String resourcePart = mainPart.substring(ipFlag);
resourcePath = resourcePart;
} else {
host = mainPart;
}
String hostVal = host;
if (port != 80) hostVal += ":" + port;
headers.put("Host", hostVal);
reqLine = "GET " + resourcePath + " 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,p_w_picpath/webp,*/*;q=0.8");
headers.put("Accept-Encoding", "gzip");
headers.put("Accept-Language", "zh-CN,zh");
headers.put("Content-Type", "text/html;charset=utf-8");
}
public void setHeader(String key, String value) {
headers.put(key, value);
}
public RespMsg req() {
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";
System.out.println(reqBody);
out.write(reqBody.getBytes());
}
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, DEF_CHARSET);
}
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;
}
}
三个辅助类:
HttpStreamReader类:
package com.zws.http;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
/**
*
* @author wensh.zhu 2017-03-11
*
*/
public class HttpStreamReader {
/**
* 行结束标识,\r\n(13,10)
*/
public static final byte[] LINE_END = {13, 10};
/**
* 响应头结束标识,\r\n\r\n(13,10,13,10)
*/
public static final byte[] ALL_END = {13, 10, 13, 10};
public static byte[] getBytes(InputStream in) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
int ind = 0;
while ((len = in.read(buffer, ind, buffer.length - ind)) > 0){
if (len == buffer.length - ind) {//full
int l = buffer.length;
byte[] newBuffer = new byte[l * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
ind = l;
} else {
ind += len;
}
}
byte[] result = new byte[ind];
System.arraycopy(buffer, 0, result, 0, ind);
return result;
}
public static byte[] readHeaders(InputStream in) throws IOException {
return read(in, ALL_END);
}
public static byte[] readLine(InputStream in) throws IOException {
return read(in, LINE_END);
}
public static byte[] read(InputStream in, byte[] endFlag) throws IOException {
byte[] buffer = new byte[1024];
int ind = 0;
int bt = 0;
while ((bt = in.read()) != -1){
buffer[ind] = (byte)bt;
if (isTailEqual(buffer, ind, endFlag))
break;
ind ++;
}
int newLen = ind + 1 - endFlag.length;
byte[] result = new byte[newLen];
System.arraycopy(buffer, 0, result, 0, newLen);
return result;
}
/**
* bts的后ends.length个字节是否和ends相等
* @param bts
* @param ends
* @return
*/
public static boolean isTailEqual(byte[] bts, int endIndex, byte[] ends){
int btsLen = endIndex + 1;
int endLen = ends.length;
if (btsLen < endLen) return false;
int tailFrom = btsLen - endLen;
int tailTo = btsLen;
byte[] tail = Arrays.copyOfRange(bts, tailFrom, tailTo);
for (int i = 0; i < endLen; i++)
if (tail[i] != ends[i])
return false;
return true;
}
}
RespHeader类:
package com.zws.http;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
*
* @author wensh.zhu 2017-03-11
*
*/
public class RespHeader {
private String respLine;
private Map<String, String> headers = new HashMap<String, String>();
public void addHeader(String head) {
if (head == null || head.length() < 1)
return;
String[] nameVal = head.split(":");
String name = nameVal[0], val = null;
if (nameVal.length > 1)
val = nameVal[1].replaceFirst(" ", "");
headers.put(name, val);
}
public String getHeader(String header) {
return headers.get(header);
}
public int getContentLenth() {
int len = 0;
String lenStr = headers.get("Content-Length");
if (lenStr == null || lenStr.length() < 1)
return len;
try {
len = Integer.parseInt(lenStr);
} catch (NumberFormatException e) {
e.printStackTrace();
}
return len;
}
public String getSessionId() {
String sessionId = null;
String val = headers.get("Set-Cookie");
if (val != null && val.length() > 0) {
String[] arrary = val.split(";");
String sessStr = arrary[0];
if (sessStr != null && sessStr.length() > 1) {
arrary = sessStr.split("=");
if (arrary.length > 1)
sessionId = arrary[1];
}
}
return sessionId;
}
/**
* 是否是分块响应
* @return
*/
public boolean isChunked() {
String val = headers.get("Transfer-Encoding");
if (val == null || val.length() < 1)
return false;
return "chunked".equals(val);
}
public String getRespLine() {
return respLine;
}
public void setRespLine(String respLine) {
this.respLine = respLine;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
@Override
public String toString() {
String str = this.respLine + "\r\n";
Set<String> keys = this.headers.keySet();
for (String key : keys) {
str += (key + ":" + this.headers.get(key) + "\r\n");
}
return str;
}
}
RespMsg类:
package com.zws.http;
/**
*
* @author wensh.zhu 2017-03-11
*
*/
public class RespMsg {
private String respCodeMsg;
private String respBody;
public String getRespCodeMsg() {
return respCodeMsg;
}
public void setRespCodeMsg(String respCodeMsg) {
this.respCodeMsg = respCodeMsg;
}
public String getRespBody() {
return respBody;
}
public void setRespBody(String respBody) {
this.respBody = respBody;
}
@Override
public String toString() {
return respCodeMsg + "\n" + respBody;
}
}
测试类:
package com.zws.http;
public class Example {
public static void main(String[] args) {
String uri = "http://localhost:8011/greeting";
SimpleHttpGet get = new SimpleHttpGet(uri);
RespMsg msg = get.req();
String respCodeMsg = msg.getRespCodeMsg();
String respBody = msg.getRespBody();
System.out.println(respCodeMsg);
System.out.println(respBody);
}
}
转载于:https://blog.51cto.com/wenshengzhu/1905510