tomcat是一个web容器,网络请求基于HTTP,HTTP底层基于socket抽象层,直接上图(盗的图)



  我就简单实现了一个socket来模拟HTTP请求与应答

package Socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by Jackie on 2017/8/2.
 *
 */
public class HttpSocket {

    private static final String OUTPUT = "<html><head><title>Example</title></head><body><p>Worked!!!</p></body></html>";
    private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" +
            "Content-Type: text/html\r\n" +
            "Content-Length: ";
    private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket(9002);
            boolean isStop = false;

            while (!isStop) {
                Socket socket = serverSocket.accept();
                InputStream in = socket.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
                String line = null;
                while ((line = bufferedReader.readLine())!=null){
                    System.out.println(line);
                    if (line.isEmpty())
                        break;
                }
                sendResponse(socket);
                socket.close();

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendResponse(Socket socket) throws IOException {
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
        bw.write(OUTPUT_HEADERS + OUTPUT.length() + OUTPUT_END_OF_HEADERS + OUTPUT);
        bw.flush();
        bw.close();
    }

    public static void main(String[] args){
        new HttpSocket().start();
    }
}

  代码的逻辑非常简单,先是获得HTTP请求,打印其HTTP的request部分,然后获得输出流,按照HTTP中response的响应格式,输出一个简单的html。最终的效果就是,在浏览器中输入http://localhost:9002/ 就会返回一个简单的html页面,效果如下图:

  


  其中有一个好玩的现象,当我在浏览器敲入localhost:9002的时候,后台程序打印出来发现浏览器发送了两次HTTP请求:

GET / HTTP/1.1
Host: localhost:9002
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: Idea-d1657464=19a93302-2aa0-4496-a546-c42fd7726ea0


GET /favicon.ico HTTP/1.1
Host: localhost:9002
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://localhost:9002/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: Idea-d1657464=19a93302-2aa0-4496-a546-c42fd7726ea0

  其中第一次请求使我们比较熟悉的,但是第二次请求我从来没注意到过,但是看了下请求的格式,好像大概的能明白请求的意图从第一行就可以看出来请求的是一个icon,我们每次打开一个网页的时候,你有没有注意到每个网页标签页左上角都会有一个icon小图标。既然遇到了这个有趣的地方,那么要去实现这个功能,程序改的也比较简单,当第二次HTTP请求的时候,我们返回一个带有图片文件的Response。程序如下:

package Socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by Jackie on 2017/8/2.
 *
 */
public class HttpSocket {

    private static final String OUTPUT = "<html><head><title>Example</title></head><body><p>Worked!!!</p></body></html>";

    private static final String OUTPUT_HEADERS = "HTTP/1.1 200 OK\r\n" +
            "Content-Type: text/html\r\n" +
            "Content-Length: ";

    private static final String OUTPUT_HEADERS_IOCN = "HTTP/1.1 200 OK\r\n" +
            "Content-Type: image/*\r\n" +
            "Content-Length: ";

    private static final String OUTPUT_END_OF_HEADERS = "\r\n\r\n";

    private static final String Icon_Location = "/Users/macbookpro/Desktop/resizeApi.png";

    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket(9002);
            boolean isStop = false;
            boolean isIconRequest = false;
            while (!isStop) {
                Socket socket = serverSocket.accept();
                InputStream in = socket.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
                String line = null;
                while ((line = bufferedReader.readLine())!=null){
                    System.out.println(line);
                    if(line.contains("GET /favicon.ico")){
                        sendIcon(Icon_Location , socket);
                        isIconRequest = true;
                    }
                    if (line.isEmpty())
                        break;
                }

                if (!isIconRequest)
                    sendResponse(socket);

                socket.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendResponse(Socket socket) throws IOException {
        OutputStream outputStream = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
        bw.write(OUTPUT_HEADERS + OUTPUT.length() + OUTPUT_END_OF_HEADERS + OUTPUT);
        bw.flush();
        bw.close();
    }

    public void sendIcon(String iconLocation , Socket socket) throws IOException {
        File file = new File(iconLocation);
        if (!file.exists())
            throw new FileNotFoundException();

        BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream(file));
        BufferedOutputStream fileOut = new BufferedOutputStream(socket.getOutputStream());

        fileOut.write(OUTPUT_HEADERS.getBytes());
        fileOut.write(String.valueOf(file.length()).getBytes());
        fileOut.write(OUTPUT_END_OF_HEADERS.getBytes());

        byte[] buf = new byte[1024];
        int size = 0;
        while ((size = fileIn.read(buf))>0){
            fileOut.write(buf , 0 , size);
        }

        fileOut.flush();
        fileOut.close();
        fileIn.close();
    }

    public static void main(String[] args) throws IOException {
        new HttpSocket().start();
    }
}
  发送图片的IO流我选择了字节流,因为在以前我尝试用字符去复制二进制图片文件时,复制完成后打不开了,提示我格式有错误,然后我选择了字节流就解决了这个问题。最终的返回页面如图:

  在标签的左上角就有了一个github小图标了》

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐