前言
上个版本我们处理了响应404页面,此版本我们将对代码进行重构。
重构思想:
与请求一样,既然响应也是由三部分构成,我们可以设计一个类, 取名:HttpResponse,并用这个类的每一个实例表示客户端发送的 相应内容。将来可以根据实际响应内容不同,对响应的对象中各部分 信息进行设置,最终发送给客户端。
实现:
1.新建类HttpResponse
2.定义结构
定义HttpResponse的结构,以及方法flushflush方法用于将当前响应对象的各部分信息最终以标准的Http响应格式发送给客户端。
代码如下:
public class HttpResponse {
private Socket socket;
private OutputStream out;
//状态行相关信息
private int statusCode = 200;
private String statusReason = "OK";
//响应头相关信息
//响应正文相关信息
private File entity; //响应正文对应的实体文件
public HttpResponse(Socket socket) {
try {
this.socket = socket;
out = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 将当前响应对象内容以一个标准的HTTP响应格式发送给客户端
*/
public void flush() {
try {
//1.发送状态行
sendStatusLine();
//2.发送响应头
sendHeaders();
//3.发送响应正文
sendContent();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送状态行
*/
private void sendStatusLine() {
try {
String line = "HTTP/1.1"+" "+statusCode+" "+statusReason;
println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送响应头
*/
private void sendHeaders() {
try {
String line = "Content-Type: text/html";
println(line);
line = "Content-Length: "+entity.length();
println(line);
//单独发送CRLF表示响应头发送完毕
out.write(13);
out.write(10);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送响应正文
*/
private void sendContent() {
try(
//利用自动关闭特性,关闭文件流
FileInputStream fis = new FileInputStream(entity);
) {
int len;
byte[] data = new byte[1024*8];
while((len = fis.read(data)) != -1) {
out.write(data, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 向客户端发送一行给定的字符串,发送该字符串后悔自动在
* 后面发送回车符与换行符。
* @param line
* @throws IOException
*/
private void println(String line) throws IOException {
out.write(line.getBytes("ISO8859-1"));
out.write(13);
out.write(10);
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public String getStatusReason() {
return statusReason;
}
public void setStatusReason(String statusReason) {
this.statusReason = statusReason;
}
public File getEntity() {
return entity;
}
public void setEntity(File entity) {
this.entity = entity;
}
}
3.设置并调用
将ClientHandler处理请求的分支根据处理结果设置HttpResponse对象内容并通过调用flush方法发送响应。代码如下:
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket) {
this.socket = socket;
}
public void run() {
try {
//1.解析请求
//实例化就是解析过程,得到的对象就表示本次请求的内容
HttpRequest request = new HttpRequest(socket);
HttpResponse response = new HttpResponse(socket);
//2.处理请求
String path = request.getUri();
System.out.println("抽象路径:"+path);
File file = new File("webapps"+path);
if (file.isFile() && file.exists()) {
System.out.println("资源已找到!");
response.setEntity(file);
} else {
System.out.println("资源不存在!");
response.setStatusCode(404);
response.setStatusReason("NotFound");
response.setEntity(new File("webapps/root/404.html"));
}
//3.响应客户端
response.flush();
System.out.println("响应客户端完毕!");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
//与客户端断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
此版本我们重构了之前在ClientHandler中的代码,并且根据不同的请求设置了不同的响应页面。
下一个版本将进入浏览器与服务端的交互过程。