一个简单的Web服务器-支持静态资源请求
目标
实现一个简单的Web服务器,能够根据HTTP请求的URL响应对应的静态资源,如果静态资源不存在则响应404。
HttpServer
使用ServerSocket实现的一个服务器,request根据socket.getInputStream()获取HTTP报文,response将响应写入socket.getOutputStream()中。
public class HttpServer { public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; private static final String SHUTDOWN_COMMAND = "/SHUTDOWN"; private static final int PORT = 8899; public HttpServer() { } public static void main(String[] args) throws IOException { HttpServer httpServer = new HttpServer(); httpServer.service(); } public void service() throws IOException { ServerSocket serverSocket = new ServerSocket(PORT); System.out.println("服务器启动:" + serverSocket); while (true) { try (Socket socket = serverSocket.accept()) { System.out.println("客户端建立连接:" + socket); Request request = new Request(socket.getInputStream()); if (Objects.isNull(request.getUri())) { continue; } if (isShutdownComment(request)) { //如果是shutdown命令,则关闭服务器 break; } Response response = new Response(request, socket.getOutputStream()); response.sendStaticResource(); // 返回静态资源 System.out.println("客户端关闭连接:" + socket); } catch (Exception e) { e.printStackTrace(); } } } private boolean isShutdownComment(Request request) { return Objects.equals(SHUTDOWN_COMMAND, request.getUri()); } }
Request
读取输入流,获取HTTP报文,并从中解析出URL,Response会根据这个URL去读取对应的静态资源
public class Request { private InputStream inputStream; /** * HTTP 报文 */ private String message; /** * HTTP 请求 URI */ private String uri; public Request(InputStream inputStream) throws IOException { parse(inputStream); } /** * 从 inputStream 中读取出报文 */ private void parse(InputStream inputStream) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line = null; while (Objects.nonNull(line = reader.readLine())) { sb.append(line).append("\n"); } this.message = sb.toString(); this.uri = parseURI(); System.out.println("-------------------------------------------"); System.out.println(message); System.out.println("-------------------------------------------"); } /** * 从报文中解析出请求 uri * * @return */ private String parseURI() { int beginIndex = message.indexOf(" "); int endIndex = message.indexOf(" ", beginIndex + 1); if (beginIndex == -1 || endIndex == -1) { return null; } return message.substring(beginIndex + 1, endIndex); } public String getUri() { return uri; } public String getMessage() { return message; } }
Response
调用 File staticResource = new File(HttpServer.WEB_ROOT, request.getUri()); 拿到对应的静态资源。
比如请求的url是 http://localhost:8899/index.html,则会去webRoot下面寻找index.html文件,如果文件不存在则返回404
public class Response { private static final String RETURN_404 = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "<h1>File Not Found</h1>"; private OutputStream outputStream; private Request request; public Response(Request request, OutputStream outputStream) { this.request = request; this.outputStream = outputStream; } /** * 发送静态资源 */ public void sendStaticResource() throws IOException { File staticResource = new File(HttpServer.WEB_ROOT, request.getUri()); //请求的静态资源路径 if (staticResource.exists()) { //静态资源存在则返回给客户端 try (FileInputStream fileInputStream = new FileInputStream(staticResource)) { int b = 0; while ((b = fileInputStream.read()) != -1) { outputStream.write(b); } } } else { //不存在返回404 outputStream.write(RETURN_404.getBytes()); } outputStream.flush(); } }
参考
1.《How Tomcat Works》 - Budi Kurniawan