1.V6(版本)
测试目标:将index.html页面发送给浏览器 从而了解HTTP的响应格式 1:用File对象表示resources下的static目录中myweb目录中的index.html 2:通过socket获取输出流 3:通过输出流将一个标准的HTTP响应内容发送给浏览器,其中就包含了index页面 在maven项目中,java的源码文件和其他文件是要分开存放的。 所有java源码文件放在:src/main/java中 而所有的其他资源文件放在:src/main/resources中 但是当编译后,IDEA会将java目录和resources目录合并保存在 target/classes中。 所以我们可以理解为java目录和resources目录就是同一个目录
1.1项目目录
1.2Java代码
1.2.1WebServerApplication(启动类)
没有改动和之前V5版本一致
1.2.2ClientHandle
package com.webserver.core;
import com.webserver.http.HttpServletRequest;
import java.io.*;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
* 该线程任务是负责与一个客户端进行一次HTTP交互
* 浏览器与服务端交互组从一问一答的原则。因此服务端处理一次HTTP交互,步骤如下:
* 1:解析请求(接受浏览器发送过来的请求内容)
* 2:处理请求(根据浏览器发送的请求理解其意图并进行对应的处理)
* 3:发送响应(将处理结果发送给浏览器)
*
*
*/
public class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
try {
//1解析请求
HttpServletRequest request = new HttpServletRequest(socket);
//2处理请求
String path = request.getUri();
//3发送响应
/*
测试目标:将index.html页面发送给浏览器
从而了解HTTP的响应格式
1:用File对象表示resources下的static目录中myweb目录中的index.html
2:通过socket获取输出流
3:通过输出流将一个标准的HTTP响应内容发送给浏览器,其中就包含了index页面
在maven项目中,java的源码文件和其他文件是要分开存放的。
所有java源码文件放在:src/main/java中
而所有的其他资源文件放在:src/main/resources中
但是当编译后,IDEA会将java目录和resources目录合并保存在
target/classes中。
所以我们可以理解为java目录和resources目录就是同一个目录
*/
//由于编译后所有内容都合并放在了target/classes下,因此从该目录开始寻找资源
File rootDir = new File(
ClientHandler.class.getClassLoader()
.getResource(".").toURI()
);
//从根目录开始定位下面保存所有静态资源的目录"static"
/*
File构造方法第一个参数为所在的父目录
意思是定位在rootDir表示的目录中有一个名为"static"的子项
*/
File staticDir = new File(rootDir,"static");
//定位static目录下myweb目录中的index.html
/*
http://localhost:8088/myweb/index.html
http://localhost:8088/myweb/classTable.html
*/
File file = new File(staticDir,path);
System.out.println("资源是否存在:"+file.exists());
/*
HTTP/1.1 200 OK(CRLF)
Content-Type: text/html(CRLF)
Content-Length: 2546(CRLF)(CRLF)
1011101010101010101......
*/
//3.1发送状态行
println("HTTP/1.1 200 OK");
//3.2发送响应头
println("Content-Type: text/html");
println("Content-Length: " + file.length());
//单独发送回车+换行表示响应头部分发送完毕了
println("");
//3.3将文件的所有字节作为正文内容发送给浏览器
FileInputStream fis = new FileInputStream(file);
OutputStream out = socket.getOutputStream();
byte[] buf = new byte[1024*10];//10kb
int len;//记录每次实际读取到的字节数
while((len = fis.read(buf)) != -1) {
out.write(buf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
} finally {
try {
//按照HTTP协议要求,一次交互后要断开连接
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void println(String line) throws IOException {
OutputStream out = socket.getOutputStream();
byte[] data = line.getBytes(StandardCharsets.ISO_8859_1);
out.write(data);//发送状态行内容
out.write(13);//发送回车符
out.write(10);//发送换行符
}
}
1.2.3HttpServletRequest
package com.webserver.http;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/**
* 请求对象
* 该类的每一个实例用于表示客户端发送过来的一个HTTP请求
* 每个请求由三部分构成:
* 请求行,消息头,消息正文
*/
public class HttpServletRequest {
private Socket socket;
//请求行的相关信息
private String method;//请求方式
private String uri;//抽象路径
private String protocol;//协议版本
//用一个Map保存所有的消息头,其中key:消息头名字,value:消息头的值
private Map<String,String> headers = new HashMap<>();
public HttpServletRequest(Socket socket) throws IOException {
this.socket = socket;
//1.1解析请求行
parseRequestLine();
//1.2解析消息头
parseHeaders();
//1.3解析消息正文
parseContent();
}
//解析请求行
private void parseRequestLine() throws IOException {
String line = readLine();
System.out.println(line);
//将请求行按照空格拆分为三部分,并赋值给三个变量
String[] data = line.split("\\s");
method = data[0];
uri = data[1];
protocol = data[2];
//测试路径:http://localhost:8088/myweb/index.html
System.out.println("method:"+method);//method:GET
System.out.println("uri:"+uri);//uri:/myweb/index.html
System.out.println("protocol:"+protocol);//protocol:HTTP/1.1
}
//解析消息头
private void parseHeaders() throws IOException {
while(true) {
String line = readLine();
if(line.isEmpty()){//读取单独读取了CRLF则停止循环
break;
}
System.out.println(line);
String[] data = line.split(":\\s");
headers.put(data[0].toLowerCase(),data[1]);
}
System.out.println(heade