เป็นที่ทราบกันดีว่าการสื่อสารระหว่างเว็บเซิร์ฟเวอร์และไคลเอนต์ใช้โปรโตคอล HTTP HTTP เป็นมาตรฐานสำหรับคำขอและการตอบสนองของไคลเอนต์และเซิร์ฟเวอร์ (TCP) เนื่องจากโปรโตคอล HTTP ขึ้นอยู่กับโปรโตคอล TCP ฉันจะใช้ซ็อกเก็ตใน Java เพื่อทำเว็บเซิร์ฟเวอร์อย่างง่ายนี้ให้สมบูรณ์ สำหรับข้อมูล HTTP โดยละเอียดเพิ่มเติมคุณสามารถปรึกษาข้อมูลที่เกี่ยวข้องเพื่อเรียนรู้เกี่ยวกับมัน
ก่อนที่จะเขียนเซิร์ฟเวอร์ลองมาดูกฎการสื่อสารระหว่างเบราว์เซอร์และเซิร์ฟเวอร์
ก่อนอื่นเราใช้ Serversocket เพื่อจำลองเซิร์ฟเวอร์เข้าถึงผ่านเบราว์เซอร์และดูเนื้อหาที่เบราว์เซอร์ร้องขอ:
นำเข้า java.io.bufferedWriter; นำเข้า java.io.inputstream; นำเข้า java.io.OutputStreamWriter; นำเข้า java.net.inetaddress; นำเข้า java.net.inetsocketaddress; นำเข้า java.net.serversocket; ทดสอบ * * @author Jianggujin * */คลาสสาธารณะ HQHTTPPROTOCOLTEST {@Test Public Void Server () พ่นข้อยกเว้น {Serversocket Serversocket = Serversocket ใหม่ (80); ซ็อกเก็ตซ็อกเก็ต = serversocket.accept (); stream inputstream = socket.getInputStream (); int r = -1; ในขณะที่ ((r = stream.read ())! = -1) {system.out.print ((char) r); -เรียกใช้กับ junit และเข้าถึงผ่านเบราว์เซอร์: http://127.0.0.1 เราจะเห็นว่าเนื้อหาคำขอของเบราว์เซอร์บนคอนโซลมีดังนี้:
รับ/http/1.1host: 127.0.0.1connection: Keep-aliveaccept: text/html, application/xhtml+xml, application/xml; q = 0.9, image/webp,*/*; q = 0.8user-agent: mozilla/5.0 Gecko) Chrome/31.0.1650.63 Safari/537.36accept-encoding: GZIP, deflate, Sdchaccept-Language: ZH-CN, ZH; q = 0.8
เพื่อวิเคราะห์เนื้อหาคำขอได้ดีขึ้นเราเขียนหน้า HTML เพื่อส่งข้อมูลบางส่วนและดูเนื้อหาคำขออีกครั้ง:
<! doctype html> <html> <head> <meta charset = "utf-8"> <title> ทดสอบ </title> </head> <body> <วิธีการฟอร์ม = "โพสต์" แอ็คชั่น = "http://127.0.0.1?test=123" type = "ส่ง"/> </form> </body> </html>
ป้อน Bob ในกล่องอินพุตคลิกปุ่มเพื่อส่งและสังเกตเอาต์พุตคอนโซล:
post/? test = 123 http/1.1host: 127.0.0.1connection: Keep-alivecontent-length: 8cache-control: max-age = 0accept: text/html, application/xhtml+xml, application/xml; q = 0.9, ภาพ/webp,*/**; (Windows NT 5.1) Applewebkit/537.36 (khtml, เช่น Gecko) Chrome/31.0.1650.63 Safari/537.36Content-type: แอปพลิเคชัน/x-www-form-urlencodedaccept-encoding
มาวิเคราะห์เนื้อหาของคำขอนี้:
บรรทัดแรก: ประกอบด้วยสามส่วนคั่นด้วยช่องว่างตรงกลางส่วนแรกคือวิธีการร้องขอ (รับโพสต์) ส่วนที่สองคือพารามิเตอร์เส้นทางการร้องขอและการสืบค้นและส่วนที่สามคือรุ่นโปรโตคอล HTTP (HTTP/1.1)
บรรทัดที่ 2 ถึงบรรทัดที่ 10: ข้อมูลส่วนหัวของคำขอชื่อและค่าของส่วนหัวคำขอถูกส่งผ่าน: แยกบรรทัดที่สิบเอ็ด: บรรทัดที่ 12 ที่ว่างเปล่า: เนื้อหาแบบฟอร์มที่ส่งเราสามารถได้ข้อสรุปต่อไปนี้: พฤติกรรมแรกของข้อมูลคำขอคือวิธีการร้องขอเส้นทางการร้องขอพารามิเตอร์แบบสอบถามและรุ่น HTTP โปรโตคอล หลังจากการแบ่งบรรทัด /r /n ข้อมูลส่วนหัวคำขอจะตามมาทันทีด้วยการแบ่งบรรทัด /r /n ข้อมูลส่วนหัวคำขอตามด้วยบรรทัดว่างหลังจากข้อมูลส่วนหัวคำขอเสร็จสิ้นและข้อมูลคำขอจะตามด้วยบรรทัดว่างทันที ควรสังเกตว่านี่เป็นเพียงการจำลองเท่านั้น สำหรับการส่งไฟล์ที่ซับซ้อน ฯลฯ ไม่ได้กล่าวถึงที่นี่และรูปแบบเนื้อหาคำขอแตกต่างกันเล็กน้อย
ณ จุดนี้เราได้รู้จักเนื้อหาที่ลูกค้าร้องขอแล้ว มาดูรูปแบบของข้อมูลการตอบกลับของเซิร์ฟเวอร์หลังจากได้รับคำขอ เราสร้างโครงการเว็บใหม่สำหรับการทดสอบและแก้ไขเนื้อหาของหน้า HTML ดังนี้:
<! doctype html> <html> <head> <meta charset = "utf-8"> <title> ทดสอบ </title> </head> <body> นี่คือหน้าทดสอบ </body> </html>
เริ่มเซิร์ฟเวอร์จากนั้นเขียนรหัสทดสอบไคลเอนต์เพื่อรับข้อมูลการส่งคืนเซิร์ฟเวอร์:
นำเข้า java.io.bufferedWriter; นำเข้า java.io.inputstream; นำเข้า java.io.OutputStreamWriter; นำเข้า java.net.serversocket นำเข้า java.net.socket; นำเข้า org.junit.test; HQHTTPPROTOCOLTEST {Public Void Server () พ่นข้อยกเว้น {Serversocket Serversocket = Serversocket ใหม่ (80); ซ็อกเก็ตซ็อกเก็ต = serversocket.accept (); stream inputstream = socket.getInputStream (); // bufferedInputStream inputStream = ใหม่ bufferedInputStream (สตรีม); int r = -1; ในขณะที่ ((r = stream.read ())! = -1) {system.out.print ((char) r); }} @Test Public Void Client () โยนข้อยกเว้น {ซ็อกเก็ตซ็อกเก็ต = ซ็อกเก็ตใหม่ ("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 ("โฮสต์: 127.0.0.1/r/n"); writer.write ("การเชื่อมต่อ: Keep-alive/r/n"); writer.write ("ยอมรับ: ข้อความ/html, แอปพลิเคชัน/xhtml+xml, application/xml; q = 0.9, image/webp,*/*; q = 0.8/r/n"); Writer.write ("ผู้ใช้ตัวแทน: Mozilla/5.0 (Windows NT 5.1) Applewebkit/537.36 (khtml, เช่น Gecko) Chrome/31.0.1650.63 Safari/537.36/R/N"); Writer.write ("ยอมรับการเข้ารหัส: gzip, deflate, sdch/r/n"); Writer.write ("ยอมรับภาษา: zh-cn, zh; q = 0.8/r/n"); writer.write ("/r/n"); Writer.flush (); stream inputstream = socket.getInputStream (); int r = -1; ในขณะที่ ((r = stream.read ())! = -1) {system.out.print ((char) r); -การรันโปรแกรมเพื่อให้เซิร์ฟเวอร์ส่งคืนเนื้อหาต่อไปนี้:
http/1.1 200 okserver: apache-coyote/1.1accept-ranges: bytesetag: w/"129-1456125361109" ล่าสุดแก้ไข: วันจันทร์, 22 ก.พ. 2016 07:16:01 GMTCONTENTETENT gmt <! doctype html> <html> <head> <head> <meta charset = "utf-8"> <title> ทดสอบ </title> </head> <body> นี่คือหน้าทดสอบ </body> </html>
ในทำนองเดียวกันลองวิเคราะห์ข้อความส่งคืนนี้:
บรรทัดแรกประกอบด้วยสามส่วนซึ่งคั่นด้วยช่องว่างตรงกลางส่วนแรกคือรุ่นโปรโตคอล HTTP (HTTP/1.1) ส่วนที่สองคือรหัสสถานะการตอบสนองและส่วนที่สามคือคำอธิบายสถานะการตอบสนองของบรรทัดที่สองไปยังบรรทัดที่เจ็ดของการตอบกลับ สรุป: สิ่งแรกคือข้อมูลคำขอ HTTP โปรโตคอลรหัสสถานะการตอบสนองและคำอธิบายสถานะการตอบกลับและข้อมูลส่วนหัวของการตอบกลับตามด้วยการแบ่งบรรทัด /r /n และข้อมูลส่วนหัวของการตอบกลับจะถูกส่งผ่านข้อมูลการตอบกลับและข้อมูลการตอบกลับ ควรสังเกตว่านอกเหนือจากการตอบกลับนี้แล้วยังมีวิธีการอื่น ๆ ที่สอดคล้องกันเช่นก้อนซึ่งไม่ได้กล่าวถึงที่นี่และคุณสามารถตรวจสอบข้อมูลที่เกี่ยวข้องได้
จนถึงตอนนี้เราได้วิเคราะห์รูปแบบเนื้อหาคำขอของลูกค้าและรูปแบบเนื้อหาที่สอดคล้องกันของเซิร์ฟเวอร์ บทความนี้จบลงที่นี่ ฉันหวังว่ามันจะเป็นประโยชน์กับการเรียนรู้ของทุกคน