shell 指令碼如何判斷檔案是否存在
HTTP協議(Hypertext Transfer Protocol,超文字傳輸協議),顧名思義,是關於如何在網路上傳輸超文字(即HTML文件)的協議。HTTP協議規定了Web的基本運作過程,以及瀏覽器與Web伺服器之間的通訊細節。HTTP協議採用客戶/伺服器通訊模式, 是目前在Internet上應用最廣泛的通訊協議之一。
如圖所示,在分層的網路體系結構中,HTTP協議位於應用層,建立在TCP/IP協議的基礎上。HTTP協議使用可靠的TCP連線,預設埠是80埠
HTTP協議規定Web的基本運作過程基於客戶/伺服器通訊模式,客戶端主動發出HTTP請求,服務端接收HTTP請求,再返回相應的HTTP響應結果。客戶端與伺服器之間的一次資訊交換包括以下過程:
(1)客戶端與伺服器端建立TCP連線
(2)客戶端發出HTTP請求。
(3)伺服器端發出相應的HTTP響應
(4)客戶端與伺服器端之間的TCP連線關閉
HTTP協議規定的資訊交換過程
HTTP協議特點
基於 請求-響應 的模式
HTTP協議規定,請求從客戶端發出,最後伺服器端響應該請求並返回。換句話說,肯定是先從客戶端開始建立通訊的,伺服器端在沒有接收到請求之前不會發送響應。從瀏覽器與Web伺服器的通訊過程中,可以看出瀏覽器應該具備以下功能:
- 請求與Web伺服器建立TCP連線
- 建立併發送HTTP請求
- 接收並解析HTTP響應
- 在視窗中展示HTML文件
Web伺服器應該具備以下功能:
- 接收來自瀏覽器的HTTP請求
- 接收並解析HTTP請求
- 建立併發送HTTP響應
Http客戶程式和Http伺服器分別由不同的軟體開發商提供,目前最常用的HTTP客戶程式包括IE、Chrome、Firefox、Opera和Netscape等,最常用的HTTP伺服器包括IIS和Apache等。
無狀態儲存
HTTP是一種不儲存狀態,即無狀態(stateless)協議。HTTP協議自身不對請求和響應之間的通訊狀態進行儲存。也就是說在HTTP這個級別,協議對於傳送過的請求或響應都不做持久化處理。使用HTTP協議,每當有新的請求傳送時,就會有對應的新響應產 生。協議本身並不保留之前一切的請求或響應報文的資訊。這是為了更快地處理大量事務,確保協議的可伸縮性,而特意把HTTP協議設計成 如此簡單的。
無連線
無連線的含義是限制每次連線只處理一個請求。伺服器處理完客戶的請求,並收到客戶的應答後,即斷開連線。採用這種方式可以節省傳輸時間,並且可以提高併發效能,不能和每個使用者建立長久的連線,請求一次相應一次,服務端和客戶端就中斷了。但是無連線有兩種方式,早期的http協議是一個請求一個響應之後,直接就斷開了,但是現在的http協議1.1版本不是直接就斷開了,而是等幾秒鐘,這幾秒鐘是等什麼呢,等著使用者有後續的操作,如果使用者在這幾秒鐘之內有新的請求,那麼還是通過之前的連線通道來收發訊息,如果過了這幾秒鐘使用者沒有傳送新的請求,那麼就會斷開連線,這樣可以提高效率,減少短時間內建立連線的次數,因為建立連線也是耗時的
簡單快速
客戶向伺服器請求服務時,只需傳送請求方法和路徑。請求方法常用的有GET、HEAD、POST、PUT、DELETE、TRACE、OPTIONS。每種方法規定了客戶與伺服器聯絡的型別不同。 由於HTTP協議簡單,使得HTTP伺服器的程式規模小,因而通訊速度很快。
其中get與post請求方式最常用
get與post請求區別
-
GET提交的資料會放在URL之後,也就是請求行裡面,以?分割URL和傳輸資料,引數之間以&相連,如EditBook?name=test1&id=123456.(請求頭裡面那個content-type做的這種引數形式,後面講) POST方法是把提交的資料放在HTTP包的請求體中.
-
GET提交的資料大小有限制(因為瀏覽器對URL的長度有限制),而POST方法提交的資料沒有限制.
-
GET與POST請求在服務端獲取請求資料方式不同,就是我們自己在服務端取請求資料的時候的方式不同了
靈活
HTTP允許傳輸任意型別的資料物件。正在傳輸的型別由Content-Type加以標記【MIME】
請求頭
請求頭包含許多有關客戶端環境和請求正文的有用資訊。例如:瀏覽器的型別、所用的語言、請求正文的型別,以及請求正文的長度等
請求頭和請求正文之間必須以空行分割。
響應頭
由三部分構成(HTTP協議的版本、狀態碼和描述;響應頭;響應正文)
狀態碼解釋
1×× 保留
2×× 表示請求成功地接收
3×× 為完成請求客戶需進一步細化請求
4×× 客戶錯誤(404,405)
5×× 伺服器錯誤
用java套接字建立HTTP客戶與伺服器程式
package edu.uestc.avatar; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.Executors; public class HttpServer { public static void main(String[] args) throws IOException, InterruptedException { int port = 8080; try(var server = new ServerSocket(port)){ System.out.println("伺服器正在監聽埠:" + server.getLocalPort()); var executor = Executors.newCachedThreadPool(); while(true) { var socket = server.accept(); executor.execute(new Thread(()->{ try { service(socket); } catch (IOException | InterruptedException e) { e.printStackTrace(); } })); } } } public static void service(Socket socket) throws IOException, InterruptedException { var input = socket.getInputStream(); Thread.sleep(500);//休眠500毫秒,等待http請求 var size = input.available(); var buffer = new byte[size]; input.read(buffer); var request = new String(buffer); System.out.println(request); /* * 解析http請求 */ //獲取http請求的第一行 var line1 = request.substring(0, request.indexOf("HTTP/1.1")); //獲取url資訊 var url = line1.split(" ")[1]; /* * http響應 */ var contentType = ""; //響應的文件型別 var suffix = url.substring(url.lastIndexOf(".") + 1); if("html".equals(suffix) || "htm".equals(suffix)) contentType = "text/html; charset=utf-8"; else if("gif".equals(suffix)) contentType = "image/gif"; else if("jpg".equals(suffix) || "jpej".equals(suffix)) contentType = "image/jpeg"; else contentType = "application/octet-stream"; var responseResult = "HTTP/1.1 200 OK\r\n"; //響應頭和響應內容中間有一個空行 var responseHeader = "Content-Type:" + contentType + "\r\n\r\n"; //定義伺服器的根路徑 var root = "public"; var resourceInput = new BufferedInputStream(new FileInputStream(root + url)); var out = socket.getOutputStream(); out.write(responseResult.getBytes()); out.write(responseHeader.getBytes()); var len = -1; var buff = new byte[1024]; while((len = resourceInput.read(buff)) != -1) { out.write(buff, 0, len); } socket.close(); resourceInput.close(); } }