主要使用Socket请求网络,并完成响应行、响应体、响应头的输出
先看结果
响应行 = HTTP/1.1 200 OK
响应头
key = Transfer-Encoding, value = chunked
key = Server, value = nginx
key = Cache-Control, value = no-cache
key = Connection, value = keep-alive
key = Vary, value = Accept-Encoding
key = P3P, value = CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
key = Date, value = Sun, 05 Aug 2018 09:45:41 GMT
key = Content-Type, value = text/html;charset=UTF-8
响应体 = {"message":"ok","nu":"111111","ischeck":"0","condition":"B00","com":"yuantong","status":"200","state":"1","data":[{"time":"2016-01-20 21:35:35","ftime":"2016-01-20 21:35:35","context":"上海市闵行区莘庄公司(13585705701)已收件","location":null}]}
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
public class MyClass {
public static void main(String[] args) throws IOException {
String path = "http://www.kuaidi100.com/query?type=yuantong&postid=111111";
// String path = "http://www.baidu.com/";
HttpUrl httpUrl = new HttpUrl(path);
Request request = new Request.Builder()
.url(httpUrl)
.addHeader("Host", httpUrl.getHost())
.addHeader("Connection", "keep-alive")
.build();
HttpConnection httpConnection = new HttpConnection(request);
HttpCodec httpCodec = new HttpCodec();
InputStream is = httpConnection.call(httpCodec);
//读取响应行
String responseLine = httpCodec.readLine(is);
System.out.println("responseLine = " + responseLine);
//读取响应头
Map<String, String> headers = httpCodec.readHeaders(is);
for (Map.Entry<String, String> entry : headers.entrySet()) {
System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
}
//响应头分为两种,一种带有Content-Length,会告诉你响应体后面有多少个字节
//一种是Transfer-Encoding:chunked
//会将响应体分成好几段
//例如
//\r\n 响应头和响应体之间的间隔
//10\r\n
//10个字节长度的数据\r\n
//15\r\n
//15个字节长度的数据\r\n
//0\r\n 结束
//\r\n
//读取响应体
int contentLength = -1;
if (headers.containsKey("Content-Length")) {
contentLength = Integer.valueOf(headers.get("Content-Length"));
}
boolean isChunked = false;
if (headers.containsKey("Transfer-Encoding")) {
isChunked = headers.get("Transfer-Encoding").equalsIgnoreCase("chunked");
}
if (contentLength > 0) {
byte[] bytes = httpCodec.readBody(is, contentLength);
System.out.println("Response = " + new String(bytes));
}else if (isChunked) {
String s = httpCodec.readChunked(is);
System.out.println("Response = " + s);
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
class HttpCodec {
private final ByteBuffer byteBuffer;
public HttpCodec() {
byteBuffer = ByteBuffer.allocate(10 * 1024);
}
/**
* 发送请求 拼接请求行、请求头
*
* @param os 输出流
* @param request 请求参数
* @throws IOException
*/
public void writeRequest(OutputStream os, Request request) throws IOException {
HttpUrl url = request.url();
StringBuffer sb = new StringBuffer();
//拼接请求行
sb.append(request.method());
sb.append(" ");
sb.append(url.getFile());
sb.append(" ");
sb.append("HTTP/1.1\r\n");
//请求头
Map<String, String> headers = request.headers();
for (Map.Entry<String, String> entry : headers.entrySet()) {
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue());
sb.append("\r\n");
}
sb.append("\r\n");
os.write(sb.toString().getBytes("UTF-8"));
os.flush();
}
public String readLine(InputStream is) throws IOException {
byte b;
byteBuffer.clear();
byteBuffer.mark();
//可能读取到一行了
boolean isMabeyEofLine = false;
while ((b = (byte) is.read()) != -1) {
byteBuffer.put(b);
if (b == 13) {
isMabeyEofLine = true;
} else if (isMabeyEofLine) {
//读取到了/n
if (b == 10) {
//获得一行数据
byte[] lineBytes = new byte[byteBuffer.position()];
byteBuffer.reset();
byteBuffer.get(lineBytes);
byteBuffer.clear();
byteBuffer.mark();
String line = new String(lineBytes);
return line;
} else {
isMabeyEofLine = false;
}
}
}
return null;
}
/**
* 读取响应头
*
* @param is
* @return
* @throws IOException
*/
public Map<String, String> readHeaders(InputStream is) throws IOException {
HashMap<String, String> headers = new HashMap<>();
while (true) {
String line = readLine(is);
if (line.equals("\r\n")) {//因为响应头和响应体中间隔了个"\r\n"
break;
}
int index = line.indexOf(":");
if (index > 0) {
String name = line.substring(0, index);
String value = line.substring(index + 2, line.length() - 2);
headers.put(name, value);
}
}
return headers;
}
public byte[] readBody(InputStream is, int len) throws IOException {
byte[] bytes = new byte[len];
int readNum = 0;
while (true) {
readNum += is.read(bytes);
if (readNum == len) {
return bytes;
}
}
}
public String readChunked(InputStream is) throws IOException {
StringBuffer sb = new StringBuffer();
int len = -1;
boolean isEmptyData = false;
while (true) {
if (len < 0) {
String line = readLine(is);
line = line.substring(0, line.length() - 2);//\r\n
len = Integer.valueOf(line, 16);
isEmptyData = len == 0;
} else {
byte[] bytes = readBody(is, len + 2);
sb.append(new String(bytes));
len = -1;
if (isEmptyData) {
return sb.toString();
}
}
}
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocketFactory;
public class HttpConnection {
private Request request;
private Socket socket;
private InputStream is;
private OutputStream os;
public HttpConnection(Request request) {
this.request = request;
}
/**
* 连接Socket
*/
public InputStream call(HttpCodec httpCodec) throws IOException {
createSocket();
//发送请求
httpCodec.writeRequest(os, request);
return is;
}
public void createSocket() throws IOException {
if (socket != null) {
return;
}
HttpUrl url = request.url();
if (url.getProtocol().equalsIgnoreCase("https")) {
socket = SSLSocketFactory.getDefault().createSocket();
} else {
socket = new Socket();
}
//连接服务器
socket.connect(new InetSocketAddress(url.getHost(), url.getPort()));
is = socket.getInputStream();
os = socket.getOutputStream();
}
}
import java.net.MalformedURLException;
import java.net.URL;
public class HttpUrl {
private String file;
private int port;
private final String protocol;
private final String host;
public String getFile() {
return file;
}
public void setFile(String file) {
this.file = file;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getProtocol() {
return protocol;
}
public String getHost() {
return host;
}
public HttpUrl(String url) throws MalformedURLException {
URL url1 = new URL(url);
host = url1.getHost();
file = url1.getFile();
file = isEmpty(file) ? "/" : file;
protocol = url1.getProtocol();
port = url1.getPort();
port = port == -1 ? url1.getDefaultPort() : port;
}
private boolean isEmpty(String file) {
if (file.length() == 0) {
return true;
}
return false;
}
}
import java.util.HashMap;
import java.util.Map;
public class Request {
HttpUrl url;
Map<String, String> headers = new HashMap<>();
String method;
public Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
}
public String method() {
return method;
}
public HttpUrl url() {
return url;
}
public Map<String, String> headers() {
return headers;
}
public final static class Builder {
HttpUrl url;
Map<String, String> headers = new HashMap<>();
String method;
public Builder() {
this.method = "GET";
}
public Builder url(HttpUrl url) {
this.url = url;
return this;
}
public Builder addHeader(String name, String value) {
headers.put(name, value);
return this;
}
public Request build() {
if (url == null) {
throw new IllegalStateException("url is null");
}
return new Request(this);
}
}
}