一,浏览器发送请求给webserver服务器
二、webserver服务器需要解析请求、处理请求、发送响应
1、解析请求:新创建ClientHandler类
1.1 实例化HttpServletRequest
HttpServletRequest request = new HttpServletRequest(socket);
1.1.1 解析请求行 parseRequestLine();
1.1.2解析消息头parseHeaders();
1.1.3 解析消息正文parseContent();
1.1.4 新建HttpServletRequest类
(1)私有变量String method,uri,protocol,requestURI,queryString,Map parsmeters,Map headers.
(2)parseRequestLine()--定义readLine()读取1行的方法,用\\s 空格来拆分line,分别赋值给method,uri,protocol。
System.out.println("请求行:" + line);
String[] data = line.split("\\s");
method = data[0];
uri = data[1];
protocol = data[2];
(3)parseRequestLine()--解析uri,用\\? , &, =拆分uri ,分别赋值给requestURI,queryString,Map parsmeters,
String[] date = uri.split("\\?");
requestURI = date[0];
if (date.length > 1) {
queryString = date[1];
date = queryString.split("&");
for (String s : date) {
String[] s2 = s.split("=");
parameters.put(s2[0], s2.length > 1 ? s2[1] : "");
}
}
(4)parseHeaders()--判断是否为空,以及用:\\s 拆分消息头,分别赋给headers的key,value
while (true) {
String line = readLine();
if (line.isEmpty()) {//如果readLine返回空字符串,说明单独读取到了回车+换行
break;
}
String[] data = line.split(":\\s");
headers.put(data[0], data[1]);
1.2 实例化HttpServletResponse
2处理请求:新建DIspatcherServlet类
2.1 处理请求service()
根据请求路径判断是否为一个业务处理?
如果是业务则实例化controller/UserController。
if ("/regUser".equals(path)) { //如果和注册页面form 中action一样
UserController controller = new UserController();
controller.reg(request, response);
} else if("/loginUser".equals(path)){
UserController controller=new UserController();
controller.login(request,response);
}
如果不是业务,根据路径去static目录下看是否存在文件,有就输出文件、状态码200(OK);
没有文件,则输出404 问题给浏览器。
File file = new File(staticDir, path);
System.out.println("该页面是否存在:" + file.exists());
if (file.isFile()) {//用户请求的资源在static目录下存在且是一个文件
response.setContentFile(file);
} else {
response.setStatusCode(404);
response.setStatusReason("NotFound");
response.setContentFile(new File(staticDir, "/root/404.html"));
}
3、发送响应:新建HttpServletResponse类
发送状态行sendStatusLine();发送响应头sendHeaders();发送响应正文sendContent();
定义变量Socket,statusCode,statusReason,headers,contentFile
定义println方法:字符输出流OutPutStream ,getBytes 转化字节,回车和换行符13,10
OutputStream out = socket.getOutputStream();
out.write(line.getBytes(StandardCharsets.ISO_8859_1));
out.write(13);//发送回车符
out.write(10);//发送换行符
状态行sendStatusLine()方法:状态码,原因
println("HTTP/1.1" + " " + statusCode + " " +statusReason);
响应头sendHeaders()方法;
headers 集合的遍历getKey,getValue分别定义key(name),value
Set<Map.Entry<String,String>> entrySet = headers.entrySet();
for(Map.Entry<String,String> e : entrySet){
String name = e.getKey();
String value = e.getValue();
println(name + ": " + value);
}
响应正文sendContent():判断文件是否存在,业务是否存在 。用FileInputStrerm,OutputStream, date,len,块读写
if(contentFile!=null) {
try (
FileInputStream fis = new FileInputStream(contentFile);
) {
OutputStream out = socket.getOutputStream();
int len;
byte[] data = new byte[1024 * 10];
while ((len = fis.read(data)) != -1) {
out.write(data,0,len);
}
}
}
定义302重定向,sendRedirect(String path)方法
statusCode=302;
statusReason="Moved Temporarily";
addHeader("Location",path);