1 引入
瀏覽器和服務器的種類都有很多,要在它們之間通訊,必定要遵循一定的准則,而http協議就是這樣的一個"准則"。
Http協議:規定了 瀏覽器 和 服務器 數據傳輸的一種格式。
當瀏覽器想要獲取服務器的服務,就會往服務器發送一個請求,這個請求就會使用Http協議規定的格式發送到服務器,而服務器收到這個請求后,也會按照Http協議規定的格式,把服務器的響應發給瀏覽器。
下面我們看一下這種"格式"的一個實例
請求的格式:
GET /day09/first HTTP/1.1 -- 請求行 Host: localhost:8080 --請求頭(多個鍵值對) User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,zh-cn;q=0.8,zh;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive --空行 name=eric&password=123456 --實體內容
響應的格式:
HTTP/1.1 200 OK --響應行
Server: Apache-Coyote/1.1 --響應頭(多個鍵值對)
Content-Type: text/html;charset=utf-8
Content-Length: 46
Date: Sat, 22 Nov 2014 01:42:06 GMT
--空行
xxxxxx --實體內容(瀏覽器主體窗口看到的部分)
現在只要注意格式即可,具體內容我們下面一一講解
2.Http請求
2.1請求行
GET /day09/first HTTP/1.1
請求行中主要有三個部分 :
1)GET 代表請求的方式。常用的有:GET請求,和 POST請求。
請求方式:GET、POST、HEAD、PUT、CONNECT、TRACE
2)/day09/first 代表請求想要獲得的資源的URI
uri : 統一資源標記符。
url:統一資源定位父。
3)HTTP/1.1 代表請求格式的http協議的版本。
http:1.0 : 當前瀏覽器和服務器建立連接后,一次連接只能發出一次請求。
http:1.1: 當前瀏覽器和服務器建立連接后,一次連接可以發出多次請求。
那么GET和POST方式為什么事最常用的? 這就要關系到我們的表單。
html表單中只支持的請求的方式只有兩個值:GET 和 POST。
下面是表單的一段代碼:
<form action="提交的地址" method="GET/POST"> 用戶名:<input type="text" name="name"/> 密碼:<input type="password" name="password"/> <input type="submit" value="提交"/> </form>
表單提交后,表單數據就會隨請求一起發送到服務器,數據寫在了請求里面,但是GET方式 和 POST方式 把數據寫在了請求內的不同地方。
Get方式
GET /day09/testGetPost.html?name=eric&password=123456 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,zh-cn;q=0.8,zh;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day09/testGetPost.html Connection: keep-alive
可以看到,Get方式提交的請求,表單的數據會寫在請求行里,並且在請求資源后用 問號 分開。
所以,表單數據會隨着顯示在瀏覽器的地址欄,Get方式不適合提交敏感數據,並且數據量不能太大,不能超過1KB.
POST方式
POST /day09/testGetPost.html HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,zh-cn;q=0.8,zh;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/day09/testGetPost.html Connection: keep-alive name=eric&password=123456
1)參數放在請求的實體內容中。參數之間以&分割。
2)POST方式可以提交敏感數據
3)POST提交數據大小沒有限制。
以上就是 請求行 中的的分析,下面我們來分析請求頭。
2.2請求頭
Accept: text/html,image/* -- 瀏覽器告訴服務器支持的數據類型
Accept-Charset: ISO-8859-1 -- 瀏覽器支持的編碼
Accept-Encoding: gzip,compress ---瀏覽器支持的數據壓縮格式
Accept-Language: en-us,zh- --瀏覽器支持的語言
Host: www.it315.org:80 --瀏覽器需要訪問的主機和端口
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT --瀏覽器最后更新的緩存時間
Referer: http://www.it315.org/index.jsp --當前請求來自於哪個資源
User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0) --瀏覽器類型
Cookie:name=eric --瀏覽器保存的cookie信息
Connection: close/Keep-Alive --瀏覽器連接的狀態。close:關閉。keep-alive:保持連接
Date: Tue, 11 Jul 2000 18:23:51 GMT --請求發出的時間
請求頭內包含了很多來自瀏覽器的信息,我們可以從請求頭得到這些信息,這些信息實際上是一些鍵值對,用這些信息來判斷瀏覽器用戶的狀態,並且利用這些信息來實現一些功能。
那么我們接收到這些封裝好的信息,如何利用代碼得到呢?
在java中有這樣的一個類,用於得到請求行里面的信息:
HttpServletRequest對象:用於得到請求信息(十分重要),然后處理,得出不同的響應。
核心方法:
請求行:
request.getMethod(); 得到請求方式
request.getRequestURI() / getRequestURL() 得到請求的資源的url
request.getProtocol() 得到協議版本
請求頭:
request.getHeader(頭名稱)
request.getHeaderNames(); 得到所有的頭
request.getHeaders(頭名稱) 得到同名頭的值
實體內容:
request.getInputStream(); 得到實體內容的一個輸入流
那么如何得到這個對象呢?我們在服務器建一個 servlet ,然后重寫一下父類的doGet()方法,doGet方法就是瀏覽器以Get方式發送請求道服務器時,服務器就會執行doGet()方法里的內容,看下面一段代碼:
public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
我們可以看到,doGet()方法的參數中,就有那么一個HttpServletRequest類型的參數,也就是說,在doGet()方法中,我們可以利用這個參數來調用上面說的HttpServletRequest對象的核心方法,來取得請求里的數據!
下面我們利用這些方法獲取 請求行 里的信息:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = request.getMethod(); System.out.println("method is :" + method); String requestURI = request.getRequestURI(); System.out.println("requestURI is :" + requestURI); String protocol = request.getProtocol(); System.out.println("protocol is :" + protocol); }
輸出結果:
method is :GET requestURI is :/MyFirstProject/TestServlet protocol is :HTTP/1.1
這樣就能獲取請求行里的信息了!
同理!獲取請求頭內的鍵值對的信息,還有實體內容的信息,也可以利用doGet()方法內的HttpServletRequest來完成,此處不一一演示。那么我們下面研究下doGet()方法!
doxxx()方法
上面說過以GET方式提交的請求,Servlet就會調用doGet()方法來處理,十分容易理解的~
所以,如果瀏覽器以POST方式來提交請求,Servlet就會調用它的doPost()方法來處理了~
對應的,請求方式有這么多種:GET、POST、HEAD、PUT、CONNECT、TRACE
以哪種方式提交的請求,Servlet就會調用doxxx()方法來處理對應的請求了~
獲取表單的數據
表單的數據會存儲在請求中:
請求行(get方式)
GET /day09/testGetPost.html?name=eric&password=123456 HTTP/1.1
實體內容(post方式)
name=eric&password=123456
細心的讀者可能會發現,上面介紹HttpServletRequest的核心方法中,雖然可以獲取請求中的數據,但是要清楚得區分出表單內容還是很麻煩,比如說我們想要獲得name的值,那么就要寫一個程序去判解析字符串,得到name的值。這顯得十分麻煩,所以,Servlet中提供了一些簡便的方法讓我們獲取表單數據。
統一的獲取請求中表單參數的方法:
request.getParameter(參數名) 獲取單個值的參數,比如獲得name的值,就這樣寫:request.getParameter("name");
request.getParameterValues(參數名) 獲取多個值的參數,有些表單一個屬性有多個值,例如你有多個愛好,那么久調用這個方法獲取愛好的多個值。
request.getParameterNames(); 獲取所有的參數,這個方法獲得表單的所有參數的名字,例如一個表單中有:name,id,hobit,address,phone等。
現實生活中,根據不同的需要,用戶提交的表單可能是用Get方式提交的,也可能用POST方式提交的,表單數據根據不同的提交方式存儲在請求的不同地方,但是我們得到表單數據后要對數據的處理是一樣的,如果在doPost()和doGet()中都寫同一個處理方法就顯得代碼太繁瑣了,那么我們如何處理這種情況?
我們可以在doPost()方法中調用doGet()方法,在doGet()判斷請求的方式,然后根據兩種請求得到數據,然后就對這些數據進行處理。
請求參數的編碼問題
1)POST方式
request.setCharacterEncoding(碼表);
用於設置獲取實體內容參數時查詢的碼表。建議放在第一 行代碼
2)Get方法
2.1 手動解碼:(推薦使用)
if("GET".equals(request.getMethod())){ ah = new String(ah.getBytes("iso-8859-1"),"utf-8"); }
2.2 修改服務器的配置文件(依賴服務器,不推薦使用)
找到%tomcat%/conf/server.xml,修改以下配置
| <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/> 加入URIEncoding屬性,設置URI后面參數的編碼 |
HTTP相應
說完了請求,我們說一下相應,如果你懂了請求里的內容,響應內容就絕對沒問題了!
響應瀏覽器想服務器發出請求,服務器作出響應,我們看以下響應的格式:
HTTP/1.1 200 OK --響應行 Server: Apache-Coyote/1.1 --響應頭(多個鍵值對) Content-Type: text/html;charset=utf-8 Content-Length: 46 Date: Sat, 22 Nov 2014 01:42:06 GMT --空行 xxxxxx
響應的格式和請求的格式相似。
響應行
由三部分組成:
Http協議版本 HTTP/1.1
狀態碼: 服務器告訴瀏覽器,請求處理的結果。
常用的狀態:
200 請求處理完成
302 客戶端需要進一步發送請求才能完成過程。通常該狀態碼與location響應頭一起使用。
404 請求的資源沒有找到
500 服務器的資源出錯。
狀態描述: 對狀態碼的補充
響應頭
Location: http://www.it315.org/index.jsp ---重定向的地址。通常和302狀態碼一起使用。 Server:apache tomcat --服務器的類型 Content-Encoding: gzip -- 服務器發送給瀏覽器的內容壓縮格式 Content-Length: 80 --服務器發送瀏覽器的數據長度 Content-Language: zh-cn --服務器發送給瀏覽器的內容語言 Content-Type: text/html; charset=GB2312 --服務器發送給瀏覽器的內容類型和編碼 Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT --服務器資源的最后修改時間 Refresh: 1;url=http://www.it315.org --定時刷新或者隔n秒跳轉頁面 Content-Disposition: attachment; filename=aaa.zip -- 告訴瀏覽器以下載方式打開資源 Transfer-Encoding: chunked Set-Cookie:SS=Q0=5Lb_nQ; path=/search --服務器發送瀏覽器的cookie信息 Expires: -1 --通知瀏覽器不使用緩存 Cache-Control: no-cache --通知瀏覽器不使用緩存 Pragma: no-cache --通知瀏覽器不使用緩存 Connection: close/Keep-Alive 連接狀態 Date: Tue, 11 Jul 2000 18:23:51 GMT 響應的發出時間
最后就是實體內容。 我們可以使用HttpServletResponse對象來操作這些內容,然后發送給瀏覽器,具體做法其實和HttpServletRequest對象類似。在此不一一講解。
