一個簡單的HTTP請求與應答基於socket
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。程式如下:
傳送圖片的IO流我選擇了位元組流,因為在以前我嘗試用字元去複製二進位制圖片檔案時,複製完成後打不開了,提示我格式有錯誤,然後我選擇了位元組流就解決了這個問題。最終的返回頁面如圖: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(); } }
在標籤的左上角就有了一個github小圖示了》