關於HTTP1.1
概述
HTTP(HyperText Transfer Protocol)超文本傳輸協議,是因特網上應用最爲廣泛的一種網絡傳輸協議,所有的WWW文件都必須遵守這個標準。
HTTP是一個基於TCP/IP通信協議來傳遞數據(HTML 文件, 圖片文件, 查詢結果等)
請求:客戶端發送給服務器端的數據
響應:服務器端發送給客戶端的數據
請求部分
一個完整的由客戶端發送給服務器的HTTP請求中包含以下的完整數據:
1.請求行:請求方式、資源路徑、使用的協議以及版本號GET/monkey.html HTTP/1.1
2.多個請求頭:對客戶端環境描述、客戶端請求的主機地址等信息
Accept - - 瀏覽器可接收的MIME類型,即文件內容類型
Accept-Charset - - 告知服務器客戶端支持的字符集
Accept-Encoding - - 瀏覽器能夠進行解碼的數據編碼方式
Accept-Language - - 瀏覽器支持的語言
Connection - - 是否需要持久連接
Cookie - - 會話相關
Referer - - 當前頁面從哪個頁面訪問過來的
3.請求空行:空行,分隔
4.請求體:內容正文(GET沒有請求體,POST有請求體)
狀態碼 | 英文名稱 | 描述 |
---|---|---|
200 | OK | 請求成功 |
400 | Bad Request | 客戶端請求的語法錯誤,服務器無法解析 |
404 | Not Found | 服務器無法根據客戶端的請求找到資源 |
500 | Internal Server Error | 服務器內部錯誤,無法完成請求 |
- 請求網址:
http://localhost:8080/monkey.html?username=monkey&password=111
- 請求參數信息全部在請求行中,請求的數據全部在瀏覽器的地址欄,在url後,請求的url長度有限制,不安全
- 參數連接:資源?參數名=參數值&參數名=參數值&…
- 請求網址:
http://localhost:8080/monkey.html
- 請求參數在請求體中,請求的數據不會出現瀏覽器的地址欄,請求的url長度沒有限制,安全
- GET請求數據在瀏覽器的地址欄,而POST不會出現。故POST比GET更安全
- POST請求的參數存放於請求體中,而GET存放於請求行中
- GET請求URL長度有限制(上限2K),而POST沒有限制。文件上傳時使用POST方式
- GET可以緩存,POST不能緩存
- 傳遞大量數據,上傳文件用POST
- 機密信息用POST,因爲POST安全性比GET高
- 僅僅是索取數據,使用GET
- 增加、修改、刪除數據,使用POST
響應部分
客戶端向服務器發送請求,服務器應當做出響應,將數據返回給客戶端
一個完整的由服務器發送給客戶端的HTTP響應中包含以下的完整數據:
1.響應行:HTTP協議版本、狀態碼、狀態英文名 如HTTP/1.1 200 OK
2.多個響應頭:對服務器的描述、對返回數據的描述(以下只舉例部分)
Location - -
Server - - 服務器名稱
Content-Encoding - - web服務器支持返回內容壓縮編碼類型
Content-Type - - 服務器告訴客戶端本次響應體數據格式以及編碼格式,text/html;charset=UTF-8
Transfer-Encoding - - 文件傳輸編碼
Refresh - - 定時刷新
Set-Cookie - - 設置HTTP Cookie
3.響應空行:空行
4.響應體:傳輸的數據
常見的200 - -成功;303 - - 重定向;400 - -Not Found,500 - - 服務器內部錯誤;405 - -沒有對應的doGET或者doPost方法
狀態碼 | 描述 |
---|---|
1** | 信息,服務器收到請求,需要客戶端繼續執行操作 |
2** | 成功,操作被成功接收並處理 |
3** | 重定向,需要進一步的操作以完成請求 |
4** | 客戶端錯誤,請求包含語法錯誤或無法完成請求 |
5** | 服務器錯誤,服務器在處理請求的過程中發生了錯誤 |
參考文檔:HTTP狀態碼參考文檔
Request和Response
Request部分
ServletRequest接口 - - 請求對象,封裝了獲取所有請求信息,如請求行、請求頭、請求實體
HttpServletRequest接口 - - 繼承了 ServletRequest接口,用於處理HTTP協議請求的方法
獲取請求行數據 GET /MyItems/demo2?username=monkey HTTP/1.1
- String getMethod() - - 返回請求方式(GET/POST)
- String getContextPath() - - 返回虛擬目錄,如/MyItems
- String getServletPath() - - 返回servlet的路徑,如/demo2
- String getQueryString() - - 返回get方式請求參數,如
- String getRequestURI() - - 返回請求行中資源名字 username=monkey
- String getRequestURI() - - 返回請求URI,如/MyItems/demo2,URI(統一資源標識符,範圍比URL大)
- StringBuffer getRequestURL() - - 返回請求URL,如http://localhost/MyItems/demo2 ,URL(統一資源定位符)
- String getProtocol() - - 返回協議版本,如HTTP/1.1
- String getRemoteAddr() - - 返回請求服務器的客戶端IP地址
獲取請求頭
- String getHeader(String name) - - 根據指定的請求頭獲取對應的請求頭值,如Host、Connection、User-Agent等等
獲取請求體數據(注:只有POST請求方式纔有請求體)
1.先獲取流對象
- BufferedReader getReader() - - 獲取字符輸入流,只能操作字符數據
- ServletInputStream getInputStream() - - 獲取字節輸入流,可以操作所有類型數據(可用於文件上傳)
2.再從流對象中取數據
例如,從登陸表單中獲取數據,返回username=monkey&password=111
/*POST or GET*/
BufferedReader br = request.getReader();
String line = null;
while((line = br.readLine())!= null){
System.out.println(line);
}
獲取請求參數(GET和POST都能使用)
- String getParameter(String name) - - 根據參數名稱獲取對應參數值,如傳username獲取值monkey
- String[] getParameterValues(String name) - - 根據參數名稱獲取該參數的多個值,返回的是數組,一般是複選框
- Enumeration getParameterNames() - - 獲取所有請求參數的名稱,如username、password、age等等,返回枚舉類型
- Map< Sting ,String[]> getParameterMap() - - 返回請求參數組成的Map集合,即鍵值對
//設置流的編碼
request.setCharacterEncoding("utf-8");
案例:獲取用戶提交的內容
<body>
<form action="/demo6" method="post">
用戶名:<input type="text" name="username"><br>
密碼:<input type="password" name="password"><br>
愛好:<input type="checkbox" name="hobby" value="逛街">逛街
<input type="checkbox" name="hobby" value="蹦迪">蹦迪
<input type="checkbox" name="hobby" value="購物">購物
<input type="checkbox" name="hobby" value="遊戲">遊戲
<br>
<input type="submit" value="註冊">
</form>
</body>
public class RequestDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String name = request.getParameter("username");
String password = request.getParameter("password");
String[] hobbies = request.getParameterValues("hobby");
System.out.println("用戶名:"+name);
System.out.println("密碼:"+password);
System.out.print("愛好:");
for(int i = 0;i < hobbies.length;i++){
System.out.print(hobbies[i]+" ");
}
System.out.println();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
一種在服務器內部的資源跳轉方式,從Servlet1請求轉發到Servlet2,Servlet完成一部分功能再跳轉到Servlet2繼續完成Servlet1不能完成的功能
request.getRequestDispatcher(String Path).forward(request,response);
//
參數:
Path - - 表示跳轉的目標資源路徑,不能是當前服務器以外的資源路徑,如百度,csdn等等
/*瀏覽器這裏是GET請求,但是我在GET裏面調用POST封裝請求和響應對象,最終是由POST輸出*/
/*從RequestDemo1請求轉發到RequestDemo2*/
@WebServlet("/demo7")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("這裏是request的POST demo7");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
@WebServlet("/demo6")
public class RequestDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo6這裏執行了");
request.getRequestDispatcher("/demo7").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
轉發特點 - - forward
- 瀏覽器地址欄路徑不發生變化
- 只能轉發到當前服務器下的資源路徑,不能是當前服務器以外的資源,如百度、csdn等
- 請求轉發只發送一個請求
域對象 - - 一個有作用範圍的對象,可以在範圍內共享數據
request域 - - 代表一次請求的範圍
作用域對象如何共享數據?
- void setAttribute(String name,Object obj) - - 設置作用域中的共享數據
- Object getAttribute(String name) - - 通過鍵獲取值
- removeAttribute(String name) - - 通過移除鍵值對
/*RequestDemo1和RequestDemo2 設置和獲取 共享數據 */
/*輸出obj的結果爲monkey*/
@WebServlet("/demo7")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object obj = req.getAttribute("v");
System.out.println(obj);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
}
@WebServlet("/demo6")
public class RequestDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("v","monkey");
request.getRequestDispatcher("/demo7").forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
Response部分
ServletResponse接口
- - 響應對象,封裝了獲取所有響應消息(狀態行,響應頭,請求實體)的方法
HttpServletResponse接口
- - 繼承了ServletResponse接口,處理HTTP協議響應的方法
設置響應消息—普通方法
- setHeader(int sc) - - 設置狀態碼
- setHeader(String name,String value) - - 設置響應頭
設置響應體
獲取輸出流(字符輸出流or字節輸出流)->使用輸出流,將數據輸出到客戶端瀏覽器
①字符輸出流 - - PrintWriter getWriter()
該方法獲取的字符輸出流對象爲PrintWriter類型,可直接輸出字符文本內容,若想要輸出內容全爲字符文本的網頁文檔,可使用getWriter()方法
②字節輸出流 - - ServletOutputStream getOutputStream()
該方法獲取的字節輸出流對象爲ServletOutputStream類型,是OutputStream的子類,可以直接輸出字節數組中的二進制數據。若想要輸出二進制格式的響應正文,就使用getOutputStream()方法,如文件下載
/*使用字節輸出流來輸出純文本數據*/
resp.setContentType("text/html;charset=utf-8");
ServletOutputStream sos = resp.getOutputStream();//獲取字節輸出流
sos.write("頭髮沒了哦".getBytes("utf-8"));//輸出純文本數據
③注意不能同時使用PrintWriter和OutputStream,比如如下代碼會報錯
OutputStream os = response.getOutputStream();
os.write("monkey".getBytes());
PrintWriter out = response.getWriter();
out.println("cat");
④中文亂碼問題解決
/*方式一
resp.setCharacterEncoding("utf-8");//獲取流對象之前,設置流的默認編碼:ISO-8859-1 設置爲其他的編碼格式
resp.setHeader("content-type","text/html;charset=utf-8"); //告知瀏覽器服務器發送消息體數據的編碼,建議瀏覽器使用該編碼解碼
PrintWriter pw = resp.getWriter();//獲取字符輸出流
pw.write("<h1>monkey<h1>");
pw.write("頭髮沒了哦");
*/
//方式二
resp.setContentType("text/html;charset=utf-8");
是一種資源跳轉方式
實現重定向
方法一:設置狀態碼+設置路徑
@WebServlet("/resDemo1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("demo1執行了哦");
resp.setStatus(302); //設置狀態碼
resp.setHeader("location","/resDemo2"); //設置路徑
}
}
@WebServlet("/resDemo2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("訪問demo1,自動跳轉到這裏的demo2");
}
}
方法二:使用直接的方法設置路徑
resp.sendRedirect("/resDemo2");
重定向的特點 - - redirect
- 地址欄發生變化
- 重定向可以訪問其他站點的資源,如百度、csdn等
- 重定向是兩次請求,不能使用request對象共享數據
ServletContext
基本概述
- ServletContext是在服務器,被所有客戶端共享
- ServletContext是當web應用啓動時,自動創建
- 當Web應用關閉/tomcat應用關閉/對Web應用reload時,都會造成ServletContext銷燬
ServletContext接口代表整個web應用,是Servlet中最大的接口,呈現了Web應用的Servlet視圖,獲得方法
ServletContext context1 = request.getServletContext();
ServletContext context2 = this.getServletContext();
1.獲取MIME類型:在互聯網通信過程中定義的一種文件數據類型,如text/html、image/jpeg
String getMimeType(String file)
- - 獲取MIME類型
2.多個Servlet之間共享數據(域對象)
setAttribute(String name,Object object)
- - 向ServletContext中存數據
getAttribute(String name)
- - 從ServletContext中獲取數據
removeAttribute(String name)
- - 從ServletContext中移除數據
/*兩類之間共享context變量*/
@WebServlet("/resDemo1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.setAttribute("v","monkey");
}
}
@WebServlet("/resDemo2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
Object obj = context.getAttribute("v");
System.out.println(obj);
}
}
3.獲取當前WEB項目中指定的資源文件
getRealPath(String str)
- - 獲取資源絕對路徑
//獲取ServletContext對象
ServletContext context = this.getServletContext();
/*
'/'代表E:\JavaWeb\out\artifacts\JavaWeb_war_exploded下的文件
如果想要訪問WEB-INF下的文件,則路徑寫'/WEB-INF/other.html'
若要訪問src下的文件,則路徑寫'/WEB-INF/classes/other.txt'
*/
//讀取web項目文件下的文件
String realPath = context.getRealPath("/monkey.txt");
System.out.println(realPath);//E:\JavaWeb\out\artifacts\JavaWeb_war_exploded\monkey.txt
//讀取該文件的內容
BufferedReader br = new BufferedReader(new FileReader(realPath));
String MyContext = br.readLine();
System.out.println(MyContext);