Java實(shí)現(xiàn)簡(jiǎn)易Web服務(wù)器
眾所周知Web服務(wù)器與客戶端之間的通信是使用HTTP協(xié)議的。HTTP是一個(gè)客戶端和服務(wù)器端請(qǐng)求和應(yīng)答的標(biāo)準(zhǔn)(TCP)。因?yàn)镠TTP協(xié)議是基于TCP協(xié)議的,所以我將使用JAVA中的Socket完成這個(gè)簡(jiǎn)易的Web服務(wù)器。關(guān)于HTTP更詳細(xì)的資料,各位可以查閱相關(guān)資料進(jìn)行了解。
在服務(wù)器編寫之前,我們還是先來(lái)看一下瀏覽器與服務(wù)器之間通信的規(guī)則到底如何。
首先,我們是用ServerSocket來(lái)模擬一個(gè)服務(wù)端,通過(guò)瀏覽器訪問(wèn),查看瀏覽器請(qǐng)求的內(nèi)容:
import java.io.BufferedWriter; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import org.junit.Test; /** * HTTP協(xié)議測(cè)試 * * @author jianggujin * */ public class HQHttpProtocolTest { @Test public void server() throws Exception { ServerSocket serverSocket = new ServerSocket(80); Socket socket = serverSocket.accept(); InputStream stream = socket.getInputStream(); int r = -1; while ((r = stream.read()) != -1) { System.out.print((char) r); } } }
使用junit運(yùn)行,并通過(guò)瀏覽器訪問(wèn):http://127.0.0.1,我們可以看到控制臺(tái)上輸出瀏覽器的請(qǐng)求內(nèi)容如下:
GET / HTTP/1.1 Host: 127.0.0.1 Connection: keep-alive Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537 .36 Accept-Encoding: gzip,deflate,sdch Accept-Language: zh-CN,zh;q=0.8
為了更好的分析請(qǐng)求內(nèi)容,我們編寫一個(gè)HTML頁(yè)面提交一些數(shù)據(jù),再次查看請(qǐng)求內(nèi)容:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>test</title> </head> <body> <form method="post" action="http://127.0.0.1?test=123"> <input type="text" name="name"/> <input type="submit"/> </form> </body> </html>
在輸入框中輸入bob,點(diǎn)擊按鈕提交,觀察控制臺(tái)輸出:
POST /?test=123 HTTP/1.1 Host: 127.0.0.1 Connection: keep-alive Content-Length: 8 Cache-Control: max-age=0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Origin: null User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537 .36 Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip,deflate,sdch Accept-Language: zh-CN,zh;q=0.8 name=bob
我們來(lái)分析一下這段請(qǐng)求內(nèi)容:
第一行:由三部分組成,中間以空格分開(kāi),第一部分為請(qǐng)求方法(GET、POST),第二部分為請(qǐng)求路徑以及查詢參數(shù),第三部分為HTTP協(xié)議版本(HTTP/1.1)
第二行到第十行:請(qǐng)求的頭信息,請(qǐng)求頭名稱與值之間通過(guò):分隔
第十一行:空行
第十二行:提交的表單內(nèi)容
綜上,我們可以得到如下結(jié)論:請(qǐng)求信息第一行為請(qǐng)求方法、請(qǐng)求路徑以及查詢參數(shù)、HTTP協(xié)議版本,通過(guò)\r\n換行后緊跟著請(qǐng)求頭信息,各頭信息之間通過(guò)\r\n換行,請(qǐng)求頭信息結(jié)束后跟著一個(gè)空行,空行之后緊跟著一行為請(qǐng)求數(shù)據(jù),需要注意的是,這里面只模擬了最簡(jiǎn)單的表單提交,至于復(fù)雜的文件提交等,這里面不討論,請(qǐng)求內(nèi)容格式略有不同。
至此,客戶端請(qǐng)求的內(nèi)容我們已經(jīng)知道了,下面我們?cè)賮?lái)看看服務(wù)端在接收到請(qǐng)求后響應(yīng)數(shù)據(jù)的格式,我們新建一個(gè)Web項(xiàng)目用于測(cè)試,編輯Html頁(yè)面內(nèi)容如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>test</title> </head> <body>this is test page. </body> </html>
啟動(dòng)服務(wù)器,然后編寫客戶端測(cè)試代碼,獲得服務(wù)端返回?cái)?shù)據(jù):
import java.io.BufferedWriter; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import org.junit.Test; /** * HTTP協(xié)議測(cè)試 * * @author jianggujin * */ public class HQHttpProtocolTest { public void server() throws Exception { ServerSocket serverSocket = new ServerSocket(80); Socket socket = serverSocket.accept(); InputStream stream = socket.getInputStream(); // BufferedInputStream inputStream = new BufferedInputStream(stream); int r = -1; while ((r = stream.read()) != -1) { System.out.print((char) r); } } @Test public void client() throws Exception { Socket socket = new Socket("127.0.0.1", 80); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())); writer.write("GET /Servlet/test.html HTTP/1.1\r\n"); writer.write("Host: 127.0.0.1\r\n"); writer.write("Connection: keep-alive\r\n"); writer.write("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"); writer.write("User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\r\n"); writer.write("Accept-Encoding: gzip,deflate,sdch\r\n"); writer.write("Accept-Language: zh-CN,zh;q=0.8\r\n"); writer.write("\r\n"); writer.flush(); InputStream stream = socket.getInputStream(); int r = -1; while ((r = stream.read()) != -1) { System.out.print((char) r); } } }
運(yùn)行程序獲得服務(wù)器返回內(nèi)容如下:
HTTP/1.1 200 OK Server: Apache-Coyote/1.1 Accept-Ranges: bytes ETag: W/"129-1456125361109" Last-Modified: Mon, 22 Feb 2016 07:16:01 GMT Content-Type: text/html Content-Length: 129 Date: Mon, 22 Feb 2016 08:08:32 GMT <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>test</title> </head> <body>this is test page. </body> </html>
同樣的,我們來(lái)分析一下這段返回消息:
第一行由三部分組成,中間以空格分開(kāi),第一部分為HTTP協(xié)議版本(HTTP/1.1),第二部分為響應(yīng)狀態(tài)碼,第三部分為響應(yīng)狀態(tài)描述
第二行到第七行為響應(yīng)頭信息,響應(yīng)頭名稱與值之間通過(guò):分隔
第八行:空行
第九行到結(jié)束:響應(yīng)內(nèi)容
綜上,我們可以得到如下結(jié)論:請(qǐng)求信息第一行為HTTP協(xié)議版本、響應(yīng)狀態(tài)碼、響應(yīng)狀態(tài)描述,通過(guò)\r\n換行后緊跟著響應(yīng)頭信息,各頭信息之間通過(guò)\r\n換行,響應(yīng)頭信息結(jié)束后跟著一個(gè)空行,空行之后緊跟著響應(yīng)數(shù)據(jù),需要注意的是,除這種響應(yīng)外,其實(shí)還有其他的相應(yīng)方式,比如chunk,此處不討論,可查閱相關(guān)資料。
到現(xiàn)在為止,我們已經(jīng)分析完了客戶端的請(qǐng)求內(nèi)容格式以及服務(wù)端相應(yīng)內(nèi)容的格式,這一篇就到此為止了,希望對(duì)大家的學(xué)習(xí)有所幫助。
- java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Web服務(wù)器實(shí)例解析
- java 與web服務(wù)器鏈接的實(shí)例
- Java 實(shí)現(xiàn) web服務(wù)器的簡(jiǎn)單實(shí)例
- AngularJS實(shí)現(xiàn)與Java Web服務(wù)器交互操作示例【附demo源碼下載】
- 基于Java web服務(wù)器簡(jiǎn)單實(shí)現(xiàn)一個(gè)Servlet容器
- 簡(jiǎn)單實(shí)現(xiàn)Java web服務(wù)器
- Java中常見(jiàn)的5種WEB服務(wù)器介紹
- Java Socket編程(五) 簡(jiǎn)單的WEB服務(wù)器
- 搭建JavaWeb服務(wù)器步驟詳解
相關(guān)文章
解決java main函數(shù)中的args數(shù)組傳值問(wèn)題
這篇文章主要介紹了解決java main函數(shù)中的args數(shù)組傳值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02Spring boot集成Go-FastDFS實(shí)現(xiàn)圖片上傳刪除等功能實(shí)現(xiàn)
這篇文章主要介紹了Spring boot集成Go-FastDFS實(shí)現(xiàn)圖片上傳刪除等功能實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析
這篇文章主要介紹了Jmeter關(guān)聯(lián)實(shí)現(xiàn)及參數(shù)化使用解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java中用enum結(jié)合testng實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)的方法示例
TestNG數(shù)據(jù)驅(qū)動(dòng)提供的參數(shù)化讓我們?cè)跍y(cè)試項(xiàng)目可以靈活根據(jù)需求建立不同的dataprovider來(lái)提供數(shù)據(jù),而真正實(shí)現(xiàn)數(shù)據(jù),頁(yè)面,測(cè)試彼此獨(dú)立而又有機(jī)結(jié)合的可能性。 下面這篇文章主要給大家介紹了Java中用enum和testng做數(shù)據(jù)驅(qū)動(dòng)的方法示例,需要的朋友可以參考借鑒。2017-01-01Java基于Rest?Assured自動(dòng)化測(cè)試接口詳解
Rest Assured 是一個(gè)基于 Java 的流行的用于測(cè)試 RESTful API 的庫(kù)。這篇文章主要介紹了Java如何基于Rest?Assured實(shí)現(xiàn)自動(dòng)化測(cè)試接口,需要的可以參考一下2023-03-034個(gè)Java8中你需要知道的函數(shù)式接口分享
Java?8?中提供了許多函數(shù)式接口,包括Function、Consumer、Supplier、Predicate?等等。本文主要來(lái)和大家介紹一下它們的具體使用,需要的可以參考一下2023-04-04Spring使用@Value注解與@PropertySource注解加載配置文件操作
這篇文章主要介紹了Spring使用@Value注解與@PropertySource注解加載配置文件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化
本篇文章主要介紹了詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09