手寫服務器系列(5) 簡單服務器優化——複雜請求的支持

     上一篇 博客中我們實現了一個簡單的服務器,真是極其簡單。實際場景中當然不可能只是訪問一下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這條線路)。

 

發佈了119 篇原創文章 · 獲贊 23 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章