1. ก่อนอื่น มาดูโครงสร้างข้อความของ http กันก่อน
1. ข้อความขอ
ข้อความคำขอ HTTP ประกอบด้วยสี่ส่วน: บรรทัดคำขอ ส่วนหัวคำขอ บรรทัดว่าง และข้อมูลคำขอ รูปต่อไปนี้แสดงรูปแบบทั่วไปของข้อความคำขอ
(1) สายคำขอ
บรรทัดคำขอประกอบด้วยสามฟิลด์: ฟิลด์วิธีการร้องขอ, ฟิลด์ URL และฟิลด์เวอร์ชันโปรโตคอล HTTP ซึ่งคั่นด้วยช่องว่าง ตัวอย่างเช่น GET /index.html HTTP/1.1
วิธีการร้องขอของโปรโตคอล HTTP ได้แก่ GET, POST, HEAD, PUT, DELETE, OPTIONS, TRACE และ CONNECT ที่นี่เราจะแนะนำวิธี GET และวิธี POST ที่ใช้บ่อยที่สุด
GET: วิธีการ GET ถูกใช้เมื่อไคลเอนต์ต้องการอ่านเอกสารจากเซิร์ฟเวอร์ วิธีการ GET ต้องการให้เซิร์ฟเวอร์วางทรัพยากรที่อยู่ตาม URL ในส่วนข้อมูลของข้อความตอบกลับและส่งกลับไปยังไคลเอนต์ เมื่อใช้เมธอด GET พารามิเตอร์คำขอและค่าที่เกี่ยวข้องจะถูกผนวกเข้ากับ URL เครื่องหมายคำถาม ("?") ใช้เพื่อแสดงถึงจุดสิ้นสุดของ URL และจุดเริ่มต้นของพารามิเตอร์คำขอ พารามิเตอร์มีจำกัด ตัวอย่างเช่น /index.jsp?id=100&op=bind
POST: สามารถใช้วิธี POST เมื่อไคลเอ็นต์ให้ข้อมูลจำนวนมากแก่เซิร์ฟเวอร์ เมธอด POST สรุปพารามิเตอร์คำขอในข้อมูลคำขอ HTTP ซึ่งปรากฏในรูปแบบของชื่อ/ค่า และสามารถส่งข้อมูลจำนวนมากได้
(2) ส่วนหัวของคำขอ
ส่วนหัวของคำขอประกอบด้วยคู่คีย์เวิร์ด/ค่า หนึ่งคู่ต่อบรรทัด และคีย์เวิร์ดและค่าคั่นด้วยเครื่องหมายทวิภาคภาษาอังกฤษ /// ส่วนหัวของคำขอแจ้งให้เซิร์ฟเวอร์ทราบเกี่ยวกับคำขอของไคลเอ็นต์ ส่วนหัวของคำขอทั่วไปคือ:
User-Agent: ประเภทเบราว์เซอร์ที่สร้างคำขอ
ยอมรับ: รายการประเภทเนื้อหาที่ลูกค้ายอมรับ
โฮสต์: ชื่อโฮสต์ที่ร้องขอ ซึ่งอนุญาตให้ชื่อโดเมนหลายชื่ออยู่ในที่อยู่ IP เดียวกัน นั่นคือโฮสต์เสมือน
(3) บรรทัดว่าง
ส่วนหัวของคำขอสุดท้ายตามด้วยบรรทัดว่าง การขึ้นบรรทัดใหม่และอักขระป้อนบรรทัดจะถูกส่งไปเพื่อแจ้งให้เซิร์ฟเวอร์ทราบว่าไม่มีส่วนหัวของคำขอที่ต้องติดตามอีกต่อไป
(4) ขอข้อมูล
ข้อมูลคำขอไม่ได้ใช้ในวิธี GET แต่ใช้วิธี POST วิธีการ POST เหมาะสำหรับสถานการณ์ที่ลูกค้าต้องกรอกแบบฟอร์ม ส่วนหัวคำขอที่ใช้บ่อยที่สุดที่เกี่ยวข้องกับข้อมูลคำขอคือ Content-Type และ Content-Length
2. ข้อความตอบกลับ
โดยทั่วไปรูปแบบของข้อความตอบกลับจะคล้ายกับข้อความคำขอ ยกเว้นว่าบรรทัดแรกจะแตกต่างออกไป ผู้อ่านสามารถค้นหาข้อมูลเบื้องต้นเกี่ยวกับประเด็นนี้บนอินเทอร์เน็ต และจะไม่ลงรายละเอียดที่นี่
2. การนำโปรแกรมไปใช้
ขั้นตอนการนำโปรแกรมไปใช้มีดังนี้:
1. รับคำขอจากเบราว์เซอร์ไคลเอนต์
2. สร้างเธรดใหม่เพื่อจัดการคำขอ
3. อ่านข้อมูลข้อความ ตรวจสอบว่าข้อความถูกต้องหรือไม่ และวิเคราะห์เนื้อหาข้อความ
4. สร้างข้อความตอบกลับและส่งไปยังลูกค้า
5. สิ้นสุดเธรดการประมวลผลและดำเนินการตามคำขอของลูกค้ารายอื่น
รหัสโปรแกรมเป็นดังนี้:
ดู plaincopy ไปที่ clipboardprint หรือไม่
นำเข้า java.net.*;
นำเข้า java.io.*;
นำเข้า java.util.*;
นำเข้า java.lang.*;
เว็บเซิร์ฟเวอร์คลาสสาธารณะ {
โมฆะคงที่สาธารณะ main (สตริง [] args) {
พอร์ตภายใน;
เซิร์ฟเวอร์ซ็อกเก็ต server_socket;
พยายาม{
พอร์ต=จำนวนเต็มparseInt(args[0]);
-
จับ (ข้อยกเว้น e){
พอร์ต=8080;
-
พยายาม{
server_socket=ใหม่ ServerSocket(พอร์ต);
System.out.println("เว็บเซิร์ฟเวอร์ทำงานบนพอร์ต"+server_socket.getLocalPort());
ในขณะที่ (จริง) {
ซ็อกเก็ต ซ็อกเก็ต=server_socket.accept();
System.out.println("ยอมรับการเชื่อมต่อใหม่"+socket.getInetAddress()+":+socket.getPort());
//สร้างเธรดสำหรับคำขอเฉพาะเพื่อจัดการคำขอ
พยายาม{
คำขอ httpRequestHandler = httpRequestHandler ใหม่ (ซ็อกเก็ต);
เธรดเธรด = เธรดใหม่ (คำขอ);
เธรด.เริ่มต้น();
-
จับ (ข้อยกเว้น e) {
System.out.println(e);
-
-
-
จับ (IOException e) {
System.out.println(e);
-
-
-
//คลาสเธรดสำหรับการประมวลผลคำขอ
คลาส httpRequestHandler ใช้งาน Runnable {
สตริงคงที่สุดท้าย CRLF="rn";
ซ็อกเก็ตซ็อกเก็ต;
อินพุตสตรีมอินพุต;
เอาท์พุตสตรีมเอาท์พุต;
BufferedReader br;
//ตรวจสอบว่าประเภทไฟล์ที่ร้องขอนั้นถูกต้องหรือไม่
ประเภทไฟล์บูลีน=true;
//พารามิเตอร์การเริ่มต้น
httpRequestHandler สาธารณะ (ซ็อกเก็ตซ็อกเก็ต) ส่งข้อยกเว้น {
this.socket=ซ็อกเก็ต;
this.input=socket.getInputStream();
this.output=socket.getOutputStream();
this.br=new BufferedReader (InputStreamReader ใหม่ (socket.getInputStream()));
-
//เริ่มกระทู้
โมฆะสาธารณะวิ่ง () {
พยายาม{
คำขอกระบวนการ ();
-
จับ (ข้อยกเว้น e) {
System.out.println(e);
-
-
//ฟังก์ชันหลักสำหรับการประมวลผลคำขอ
กระบวนการขอโมฆะส่วนตัว () พ่นข้อยกเว้น {
ในขณะที่ (จริง) {
สตริง headerLine=br.readLine();
System.out.println("คำขอของลูกค้าคือ"+headerLine);
ถ้า(headerLine.equals(CRLF)||headerLine.equals(""))
หยุดพัก;
StringTokenizer s=StringTokenizer ใหม่ (headerLine);
สตริง temp=s.nextToken();
ถ้า(temp.equals("GET")){
ชื่อไฟล์สตริง=s.nextToken();
ชื่อไฟล์ = "" + ชื่อไฟล์;
FileInputStream fis=null;
ไฟล์บูลีนมีอยู่ = true;
if(!(fileName.endsWith(".htm"||fileName.endsWith(".html")))
-
นี้.fileType=false;
พยายาม{
fis=new FileInputStream("error.html");
-
catch (FileNotFoundException e) {
fileExists=false;
-
-
อื่น{
พยายาม{
fis=new FileInputStream(ชื่อไฟล์);
-
catch (FileNotFoundException e) {
fileExists=false;
-
-
String serverLine = "เซิร์ฟเวอร์: เว็บเซิร์ฟเวอร์ Java แบบธรรมดา";
สตริง statusLine=null;
สตริง contentTypeLine=null;
เอนทิตีสตริงร่างกาย=null;
สตริง contentLengthLine = "ข้อผิดพลาด";
ถ้า (fileExists&&this.fileType){
statusLine="HTTP/1.0 200 ตกลง"+CRLF;
contentTypeLine = "ประเภทเนื้อหา:" + this.contentType (ชื่อไฟล์) + CRLF;
contentLengthLine="ความยาวเนื้อหา:"+(จำนวนเต็มใหม่(fis.available())).toString()+CRLF;
-
อื่น{
ถ้า(fileExists&&this.fileType==false){
statusLine="HTTP/1.0 400 คำขอไม่ถูกต้อง"+CRLF;
contentTypeLine="ข้อความ/html";
enterBody="<HTML>400 ไม่ใช่ BadRequest</TITLE></HEAD>"+
"<BODY>400 คำขอไม่ถูกต้อง"+
"<br>การใช้งาน:http://yourHostName:port/"+
"fileName.html</BODY></HTML>";
-
อื่นถ้า (fileExists==false){
statusLine="HTTP/1.0 404 ไม่พบ"+CRLF;
contentTypeLine="ข้อความ/html";
enterBody="<HTML>404 ไม่พบ</TITLE></HEAD>"+
"<BODY>404 ไม่พบ"+
"<br>การใช้งาน:http://yourHostName:port/"+
"fileName.html</BODY></HTML>";
-
-
เอาท์พุต.เขียน(statusLine.getBytes());
เอาท์พุต.เขียน(serverLine.getBytes());
เอาท์พุต.เขียน(contentTypeLine.getBytes());
เอาท์พุต.เขียน(contentLengthLine.getBytes());
เอาท์พุต.เขียน(CRLF.getBytes());
ถ้า (fileExists&&this.fileType){
sendBytes (fis, เอาต์พุต);
fis.ปิด();
-
อื่น{
เอาท์พุต.เขียน(entityBody.getBytes());
-
-
-
พยายาม{
เอาท์พุท.ปิด();
br.ปิด();
ซ็อกเก็ต.ปิด();
-
catch(ข้อยกเว้นจ){}
-
//ส่งเพจที่ลูกค้าร้องขอ
โมฆะคงที่ส่วนตัว sendBytes (FileInputStream fis, OutputStream os) ส่งข้อยกเว้น {
ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [1024];
ไบต์ int=0;
ในขณะที่((ไบต์=fis.read(บัฟเฟอร์))!=-1){
os.write(บัฟเฟอร์,0,ไบต์);
-
-
//ตั้งค่าเนื้อหาของ contentType
ประเภทเนื้อหาสตริงคงที่ส่วนตัว (ชื่อไฟล์สตริง) {
if(fileName.endsWith(".htm")||fileName.endsWith(".html")){
กลับ "ข้อความ/html";
-
กลับ "ชื่อไฟล์";
-