# HTTP協議入門——1.1版本
### 基本概述
????超文本傳輸協議(HTTP,HyperText?Transfer?Protocol)是互聯網上應用最為廣泛的一種網絡協議。所有的WWW文件都必須遵守這個標準。
????HTTP協議(HyperText?Transfer?Protocol,超文本傳輸協議)是用于從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議。它可以使瀏覽器更加高效,使網絡傳輸減少。它不僅保證計算機正確快速地傳輸超文本文檔,還確定傳輸文檔中的哪一部分,以及哪部分內容首先顯示(如文本先于圖形)等。
????HTTP是客戶端瀏覽器或其他程序與Web服務器之間的應用層通信協議。在Internet上的Web服務器上存放的都是超文本信息,客戶機需要通過HTTP協議傳輸所要訪問的超文本信息。HTTP包含命令和傳輸信息,不僅可用于Web訪問,也可以用于其他因特網/內聯網應用系統之間的通信,從而實現各類應用資源超媒體訪問的集成。
?
### 長連接和短連接的區別
解釋1
所謂長連接指建立SOCKET連接后不管是否使用都保持連接,但安全性較差,???
所謂短連接指建立SOCKET連接后發送后接收完數據后馬上斷開連接,一般銀行都使用短連接
解釋2
長連接就是指在基于tcp的通訊中,一直保持連接,不管當前是否發送或者接收數據。???
而短連接就是只有在有數據傳輸的時候才進行連接,客戶-服務器通信/傳輸數據完畢就關閉連接。
解釋3
長連接和短連接這個概念好像只有移動的CMPP協議中提到了,其他的地方沒有看到過。???
通信方式???
各網元之間共有兩種連接方式:長連接和短連接。所謂長連接,指在一個TCP連接上可以連續發送多個數據包,在TCP連接保持期間,如果沒有數據包發送,需要雙方發檢測包以維持此連接。短連接是指通信雙方有數據交互時,就建立一個TCP連接,數據發送完成后,則斷開此TCP連接,即每次TCP連接只完成一對?CMPP消息的發送。???
現階段,要求ISMG之間必須采用長連接的通信方式,建議SP與ISMG之間采用長連接的通信方式。
解釋4
短連接:比如http的,只是連接、請求、關閉,過程時間較短,服務器若是一段時間內沒有收到請求即可關閉連接。???
長連接:有些服務需要長時間連接到服務器,比如CMPP,一般需要自己做在線維持。
?
參考文章:[http://blog.csdn.net/shine0181/article/details/7799754](http://blog.csdn.net/shine0181/article/details/7799754)
?
### HTTP請求部分
#### 基本結構
GET?/q547550831?viewmode=contents?HTTP/1.1?[請求行]
Host:?blog.csdn.net?[消息頭]?消息名:內容
Connection:?keep-alive?
Cache-Control:?max-age=0?
Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8?
User-Agent:?Mozilla/5.0?(Windows?NT?10.0;?WOW64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/45.0.2454.101?Safari/537.36?
Referer:?http://blog.csdn.net/q547550831?viewmode=contents?
Accept-Encoding:?gzip,?deflate,?sdch?
Accept-Language:?zh-CN,zh;q=0.8
PS:這是我博客主頁的請求頭,但是這并不代表每個網頁的請求頭都是這一樣的。
#### 請求方式
? ? 請求方式有:
POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT,CONNECT等
參考文檔:[http://tools.jb51.net/table/http_request_method](http://tools.jb51.net/table/http_request_method)
常用的有:POST和GET
#### 請求消息頭
Host:?blog.csdn.net?[主機名]
Connection:?keep-alive?[連接狀態:保持連接]
Cache-Control:?max-age=0?[指定請求和響應遵循的緩存機制:查看是否有修改并選擇更新否]
Accept:?text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8?[可接受的格式]
User-Agent:?Mozilla/5.0?(Windows?NT?10.0;?WOW64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/45.0.2454.101?Safari/537.36?[瀏覽器內核]
Referer:?[http://blog.csdn.net/q547550831?viewmode=contents](http://blog.csdn.net/q547550831?viewmode=contents)?[從哪個網頁跳轉到這個網頁來的,可以用來防盜鏈]
Accept-Encoding:?gzip,?deflate,?sdch?[可接收的壓縮格式]
Accept-Language:?zh-CN,zh;q=0.8?[瀏覽器支持的語言]
?
PS:請求是指瀏覽器發出向服務器發出,所以這些信息都是瀏覽器的信息。請求頭遠遠不止這幾種,可以參考該文檔:[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
?
案例:防止盜鏈
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.println("<a href='http://127.0.0.1:8080/servlet1/Servlet5'>連接到Servlet5</a>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
~~~
package com.pc;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
// 通過request對象來獲取http請求信息
// 取出Host
String host = request.getHeader("Host");
out.println("host=" + host);
// 限制用戶
// 獲取用戶瀏覽器的Referer
// referer可以防止盜鏈,通過判斷鏈接來至哪里
String referer = request.getHeader("Referer");
if(referer == null || !referer.startsWith("http://127.0.0.1:8080/servlet1")){
out.println("非法盜鏈");
} else {
out.println("referer=" + referer);
}
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 一般開發人員習慣把doGet()和doPost()合二為一
this.doGet(request, response);
}
public void init() throws ServletException {
// Put your code here
}
}
~~~
PS:該案例中只能允許http://127.0.0.1:8080/servlet1開頭的網址進行訪問Servlet5
### HTTP響應部分
#### 基本結構
HTTP/1.1?200?OK?[狀態行]
Server:?openresty?[消息名]?消息名:內容
Date:?Fri,?01?Jan?2016?08:11:04?GMT?
Content-Type:?text/html;?charset=utf-8?
Transfer-Encoding:?chunked?
Connection:?keep-alive?
Vary:?Accept-Encoding?
Cache-Control:?private?
Set-Cookie:?uuid=5cad65d6-7a99-4b15-a6e6-5c50e584ca77;?expires=Sat,?02-Jan-2016?08:13:49?GMT;?path=/?
Set-Cookie:?ViewMode=contents;?path=/?
Content-Encoding:?gzip
**--------------這是一個空行**
**消息體**
?
#### 響應狀態碼
? ? 響應狀態碼分別為1,2,3,4,5開頭的三位數字
<table><tbody><tr><td valign="center"><p style="text-align:left">1** ? ? ? ? ? ? ? ? ? ? ??</p></td><td valign="center"><p style="text-align:left">信息,服務器收到請求,需要請求者繼續執行操作</p></td></tr><tr><td valign="center"><p style="text-align:left">2** ? ? ? ? ? ? ? ? ? ? ?</p></td><td valign="center"><p style="text-align:left">成功,操作被成功接收并處理</p></td></tr><tr><td valign="center"><p style="text-align:left">3** ? ? ? ? ? ? ? ? ? ? ?</p></td><td valign="center"><p style="text-align:left">重定向,需要進一步的操作以完成請求</p></td></tr><tr><td valign="center"><p style="text-align:left">4** ? ? ? ? ? ? ? ? ? ? ?</p></td><td valign="center"><p style="text-align:left">客戶端錯誤,請求包含語法錯誤或無法完成請求</p></td></tr><tr><td valign="center"><p style="text-align:left">5** ? ? ? ? ? ? ? ? ? ? ?</p></td><td valign="center"><p style="text-align:left">服務器錯誤,服務器在處理請求的過程中發生了錯誤</p></td></tr></tbody></table>
?
PS:常見的有200(成功),303(重定向),400(Not?Found),500(服務器內部錯誤)
可以參考該文檔:[http://tools.jb51.net/table/http_status_code](http://tools.jb51.net/table/http_status_code)
?
#### 響應消息頭
Server:?openresty?[服務器名稱]
Date:?Fri,?01?Jan?2016?08:11:04?GMT?[原始服務器消息發出的時間]
Content-Type:?text/html;?charset=utf-8?[返回內容的MIME類型]
Transfer-Encoding:?chunked?[文件傳輸編碼]
Connection:?keep-alive?[連接狀態:保持連接]
Vary:?Accept-Encoding?[告訴下游代理是使用緩存響應還是從原始服務器請求]
Cache-Control:?private?[告訴所有的緩存機制是否可以緩存及哪種類型]
Set-Cookie:?uuid=********;?expires=Sat,?02-Jan-2016?08:13:49?GMT;?path=/?[設置Http?Cookie]
Set-Cookie:?ViewMode=contents;?path=/?[設置Http?Cookie]
Content-Encoding:?gzip?[web服務器支持的返回內容壓縮編碼類型]
?
PS:可以參考該文檔[http://tools.jb51.net/table/http_header](http://tools.jb51.net/table/http_header)
### 緩存機制
? ??瀏覽器默認情況下,會緩存所訪問的頁面,這樣會出現一個問題:如果用戶習慣把光標停留在地址欄,然后回車來取頁面,就會默認調用cache中取數據。
?
案例1、有些網站要求及時性很高,因此要求不緩存頁面。
//指定該頁面不緩存?Ie
response.setDateHeader("Expires",?-1);【針對IE瀏覽器設置不緩存】
//為了保證兼容性.
response.setHeader("Cache-Control",?"no-cache");【針對火狐瀏覽器等】
response.setHeader("Pragma",?"no-cache");【其他瀏覽器】
?
案例2、有些網站要求網頁緩存一定時間,比如緩存一個小時
response.setDateHeader("Expires",?System.currentTimeMillis()+3600*1000);?//后面一個參數表示設置的緩存保持時間,-1表示永遠不緩存
### Content-Type消息頭
? ??Content-Type,內容類型,一般是指網頁中存在的Content-Type,用于定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什么形式、什么編碼讀取這個文件
PS:其作用就是告訴瀏覽器,該服務器返回的網頁中消息體是什么格式的,該以什么編碼格式來讀取這個網頁。
因為該類型很多,故給出參考文檔,以備后用:[http://tools.jb51.net/table/http_content_type](http://tools.jb51.net/table/http_content_type)
案例1:定時刷新Refresh的使用
?response.setHeader("Refresh",?"5;url=/servletPro/Servlet2");?//?5秒后刷新并跳轉到url后的鏈接。通過這個可以實現頁面定時刷新。
?
案例2:文件下載
~~~
package com.pc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Servlet7 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
// 演示下載文件
response.setHeader("Content-Disposition", "attachment; filename=EVO_120G.jpg");
// 打開文件
// 1.獲取到要下載文件的全路徑
String path = this.getServletContext().getRealPath("/EVO_120G.jpg");
// 測試
System.out.println("path=" + path);
// 2.創建文件輸入流
FileInputStream fis = new FileInputStream(new File(path));
// 做一個緩沖字符數組
byte buff[] = new byte[1024];
int length = 0;
// 3.指向response的輸出流
OutputStream os = response.getOutputStream();
// 4.循環讀出
// length表示每次實際讀入的字節數
while((length = fis.read(buff)) != -1){
os.write(buff, 0, length);
}
// 關閉
os.close();
fis.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
~~~
?
----------參考《韓順平.細說Servlet》