上一篇 博客中我们实现了一个简单的服务器,真是极其简单。实际场景中当然不可能只是访问一下http://localhost:8080/。本篇博客,我们的目的是优化简单服务器,让它支持复杂请求。
1. 优化HttpRequest
我们先来看看,目前的服务器对复杂get请求的支持。我们通过浏览器访问地址 http://localhost:8080/hello.do?id=123&name=456 ,控制台输出如下:
可以看到,参数还是拼接在地址后面的,我们拿到的并不是纯粹的路径,所以第一个需要优化的地址,就是截取地址和解析参数了。下面是修改后的HttpRequest:
package com.zlyx.easy.server.http;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
public class HttpRequest {
/**
* 请求方式
*/
private String method;
/**
* http地址
*/
private String httpUrl;
/**
* 请求地址
*/
private String requetUrl;;
/**
* 参数
*/
private Map<String, String> paramMap = new HashMap<String, String>();
public HttpRequest(InputStream in) throws IOException {
InputStreamReader isReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(isReader);
String string = bufferedReader.readLine();
String[] httpInfos = string.split(" ");
this.method = httpInfos[0];
this.httpUrl = httpInfos[1];
int indexOf = httpInfos[1].indexOf("?");
if (indexOf != -1) {
this.requetUrl = httpInfos[1].substring(0, indexOf);
ResoveParams(httpInfos[1].substring(indexOf + 1));
} else {
this.requetUrl = httpInfos[1];
}
}
private void ResoveParams(String str) {
String[] params = str.split("&");
for (String p : params) {
String[] split = p.split("=");
if (split[0] != null) {
paramMap.put(split[0], split[1]);
}
}
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getHttpUrl() {
return httpUrl;
}
public void setHttpUrl(String httpUrl) {
this.httpUrl = httpUrl;
}
public String getRequetUrl() {
return requetUrl;
}
public void setRequetUrl(String requetUrl) {
this.requetUrl = requetUrl;
}
public Map<String, String> getParamMap() {
return paramMap;
}
public void setParamMap(Map<String, String> paramMap) {
this.paramMap = paramMap;
}
@Override
public String toString() {
return "HttpRequest [method=" + method + ", httpUrl=" + httpUrl + ", requetUrl=" + requetUrl + ", paramMap="
+ paramMap + "]";
}
}
修改HttpServlet的doGet方法,如下:
/**
* 处理get请求
*
* @throws IOException
*/
public void doGet() throws IOException {
System.out.println(request);
response.write(String.valueOf(request.hashCode()));
}
重新发起请求,控制台输出如下:
可以看到,我们得到了期望的结果。
2. 优化HttpServlet
实际场景中,请求方式有post、get等八种。目前我们只支持doGet,很明显这是不合理的。所以接下来,我们需要优化这部分内容,支持更多请求类型:
package com.zlyx.easy.server.servlet;
import java.io.IOException;
import java.net.Socket;
import com.zlyx.easy.server.http.HttpRequest;
import com.zlyx.easy.server.http.HttpResponse;
public class HttpServlet {
private String method;
private HttpRequest request;
private HttpResponse response;
private HttpServlet(HttpRequest request, HttpResponse response) throws IOException {
this.request = request;
this.response = response;
this.method = request.getMethod();
}
/**
* 处理请求
*
* @param request
* @param response
* @throws IOException
*/
private void doGet() throws IOException {
System.out.println(request);
response.write(String.valueOf(request.hashCode()));
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public HttpRequest getRequest() {
return request;
}
public void setRequest(HttpRequest request) {
this.request = request;
}
public HttpResponse getResponse() {
return response;
}
public void setResponse(HttpResponse response) {
this.response = response;
}
public static void doService(Socket socket) throws IOException {
HttpRequest request = new HttpRequest(socket.getInputStream());
HttpResponse response = new HttpResponse(socket.getOutputStream());
new HttpServlet(request, response).doGet();
}
}
修改后的代码,HttpServlet构造方法被私有化,同时,对外提供doService()方法来完成方法调用(所有的请求类型都会走Get这条线路)。