通过上文的结论,我们可以将请求数据和响应数据进行封装,让代码更具扩展性和阅读性。
4.1 封装请求对象 public class Request { // 常量(回车+换行) private static final String RN = "\r\n"; private static final String GET = "get"; private static final String POST = "post"; private static final String CHARSET = "GBK"; // 请求方式 private String method = ""; // 请求 url private String url = ""; // 请求参数 private Map<String, List<String>> parameterMap; private InputStream in; private String requestInfo = ""; public Request() { parameterMap = new HashMap<>(); } public Request(InputStream in) { this(); this.in = in; try { byte[] data = new byte[10240]; int len = in.read(data); requestInfo = new String(data, 0, len); } catch (IOException e) { return; } // 分析头信息 this.analyzeHeaderInfo(); } /** * 分析头信息 */ private void analyzeHeaderInfo() { if (this.requestInfo == null || "".equals(this.requestInfo.trim())) { return; } // 第一行请求数据: GET /login?username=aaa&password=bbb HTTP/1.1 // 1.获取请求方式 String firstLine = this.requestInfo.substring(0, this.requestInfo.indexOf(RN)); int index = firstLine.indexOf("http://www.likecs.com/"); this.method = firstLine.substring(0,index).trim(); String urlStr = firstLine.substring(index,firstLine.indexOf("HTTP/1.1")).trim(); String parameters = ""; if (GET.equalsIgnoreCase(this.method)) { if (urlStr.contains("?")) { String[] arr = urlStr.split("\\?"); this.url = arr[0]; parameters = arr[1]; } else { this.url = urlStr; } } else if (POST.equalsIgnoreCase(this.method)) { this.url = urlStr; parameters = this.requestInfo.substring(this.requestInfo.lastIndexOf(RN)).trim(); } // 2. 将参数封装到 map 中 if ("".equals(parameters)) { return; } this.parseToMap(parameters); } /** * 封装参数到 Map 中 * @param parameters */ private void parseToMap(String parameters) { // 请求参数格式:username=aaa&password=bbb&likes=1&likes=2 StringTokenizer token = new StringTokenizer(parameters, "&"); while(token.hasMoreTokens()) { // keyValue 格式:username=aaa 或 username= String keyValue = token.nextToken(); String[] kv = keyValue.split("="); if (kv.length == 1) { kv = Arrays.copyOf(kv, 2); kv[1] = null; } String key = kv[0].trim(); String value = kv[1] == null ? null : this.decode(kv[1].trim(), CHARSET); if (!this.parameterMap.containsKey(key)) { this.parameterMap.put(key, new ArrayList<>()); } this.parameterMap.get(key).add(value); } } /** * 根据参数名获取多个参数值 * @param name * @return */ public String[] getParameterValues(String name) { List<String> values = null; if ((values = this.parameterMap.get(name)) == null) { return null; } return values.toArray(new String[0]); } /** * 根据参数名获取唯一参数值 * @param name * @return */ public String getParameter(String name) { String[] values = this.getParameterValues(name); if (values == null) { return null; } return values[0]; } /** * 解码中文 * @param value * @param code * @return */ private String decode(String value, String charset) { try { return URLDecoder.decode(value, charset); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return null; } public String getUrl() { return url; } } 4.2 封装响应对象 public class Response { // 常量 private static final String BLANK = " "; private static final String RN = "\r\n"; // 响应内容长度 private int len; // 存储头信息 private StringBuilder headerInfo; // 存储正文信息 private StringBuilder contentInfo; // 输出流 private BufferedWriter bw; public Response() { headerInfo = new StringBuilder(); contentInfo = new StringBuilder(); len = 0; } public Response(OutputStream os) { this(); bw = new BufferedWriter(new OutputStreamWriter(os)); } /** * 设置头信息 * @param code */ private void setHeaderInfo(int code) { // 响应头信息 headerInfo.append("HTTP/1.1").append(BLANK).append(code).append(BLANK); if ("200".equals(code)) { headerInfo.append("OK"); } else if ("404".equals(code)) { headerInfo.append("NOT FOUND"); } else if ("500".equals(code)) { headerInfo.append("SERVER ERROR"); } headerInfo.append(RN); headerInfo.append("Content-Length:").append(len).append(RN); headerInfo.append("Content-Type:text/html").append(RN); headerInfo.append("Date:").append(new Date()).append(RN); headerInfo.append("Server:nginx/1.12.1").append(RN); headerInfo.append(RN); } /** * 设置正文 * @param content * @return */ public Response print(String content) { contentInfo.append(content); len += content.getBytes().length; return this; } /** * 设置正文 * @param content * @return */ public Response println(String content) { contentInfo.append(content).append(RN); len += (content + RN).getBytes().length; return this; } /** * 返回客户端 * @param code * @throws IOException */ public void pushToClient(int code) throws IOException { // 设置头信息 this.setHeaderInfo(code); bw.append(headerInfo.toString()); // 设置正文 bw.append(contentInfo.toString()); bw.flush(); } public void close() { try { bw.close(); } catch (IOException e) { e.printStackTrace(); } } }JavaSE 手写 Web 服务器(一) (2)
内容版权声明:除非注明,否则皆为本站原创文章。