目标

实现一个简单的Web服务器,能够根据HTTP请求的URL响应对应的静态资源,如果静态资源不存在则响应404。

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

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

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄