接上篇,代码已经能处理简单的请求,但走读一下代码,会发现这些代码非常粗糙,可改动的地方非常多,本篇先对HttpServlet进行优化
上上篇中HttpServer类担当2个责任,
1:负责接收客户端发起的请求
2:解析并响应请求。
按照单一类设计原则应该给予拆分,参考tomcat源码,HttpServer类可以分为HttpConnector类和HttpProcessor类,前者仅负责接收各类请求,后者解析并响应请求。同时添加一个启动类Boostrap
新增类:HttpConnector
/**
* 负责监听端口,接收请求信息,原先HttpServer类拆分而成
*/
public class HttpConnector implements Runnable {
// 停止记号
private boolean stopped;
// 处理
private String scheme = "http";
public String getScheme() {
return scheme;
}
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
while (!stopped) {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (Exception e) {
continue;
}
//处理请求
HttpProcessor processor = new HttpProcessor(this);
processor.process(socket);
}
}
public void start() {
Thread thread = new Thread(this);
thread.start();
}
}
说明:类实现了runable接口, 其目的非常简单,后续对项目升级时使用, 比如并发请求时,使用线程的方式处理。
新增类:HttpProcessor
/**
* 负责解析请求信息,调用StaticResouceProcessor跟ServletProcessor处理响应 ,原先HttpServer类拆分而成
*/
public class HttpProcessor {
private HttpConnector connector;
private HttpRequest request;
private HttpResponse response;
private HttpRequestLine requestLine = new HttpRequestLine();
public HttpProcessor(HttpConnector connector) {
this.connector = connector;
}
// 响应请求
public void process(Socket socket) {
SocketInputStream input = null;
OutputStream output = null;
try {
input = new SocketInputStream(socket.getInputStream(), 2048);
output = socket.getOutputStream();
request = new HttpRequest(input);
response = new HttpResponse(output);
response.setRequest(request);
response.setHeader("Server", "Pyrmont Servlet Container");
parseRequest(input, output);
parseHeaders(input);
// 响应请求
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void parseRequest(SocketInputStream input) throws IOException {
//读取请求数据,封装成reauestLine对象
input.readRequestLine(requestLine);
String method =
new String(requestLine.method, 0, requestLine.methodEnd);
String protocol = new String(requestLine.protocol, 0, requestLine.protocolEnd);
if (method.length() < 1 || requestLine.uriEnd < 1) {
throw new RuntimeException("解析请求出错");
}
request.setMethod(method);
request.setProtocol(protocol);
//对uri进行拆分,分uri + 查询参数
String uri = null;
int question = requestLine.indexOf("?");
if (question >= 0) {
request.setQueryString(new String(requestLine.uri, question + 1,
requestLine.uriEnd - question - 1));
uri = new String(requestLine.uri, 0, question);
}
else {
request.setQueryString(null);
uri = new String(requestLine.uri, 0, requestLine.uriEnd);
}
request.setRequestURI(uri);
System.out.println("method:" + request.getMethod());
System.out.println("protocol:" + request.getProtocol());
System.out.println("uri:" + request.getRequestURI());
System.out.println("queryString:" + request.getQueryString());
}
/**
* 解析请求头信息
*
* @param input
*/
private void parseHeaders(SocketInputStream input) throws IOException {
while (true) {
HttpHeader header = new HttpHeader();
input.readHeader(header);
if (header.nameEnd == 0) {
if (header.valueEnd == 0) {
return;
} else {
throw new RuntimeException("解析请求头报错");
}
}
String name = new String(header.name, 0, header.nameEnd);
String value = new String(header.value, 0, header.valueEnd);
request.addHeader(name, value);
if (name.equals("content-length")) {
int n = -1;
try {
n = Integer.parseInt(value);
} catch (Exception e) {
throw new RuntimeException("解析请求头报错");
}
request.setContentLength(n);
} else if (name.equals("content-type")) {
request.setContentType(value);
}
}
}
}
新增类:Boostrap
用于启动tomcat
public final class Bootstrap {
public static void main(String[] args) {
// 服务器启动
HttpConnector connector = new HttpConnector();
connector.start();
}
}
