Tomcat的response
阿新 • • 發佈:2018-11-01
1. response組成
- response有三部分組成:響應行、響應頭、響應體
1.1 response物件
- HttpServletResponse 物件封裝了向客戶端傳送資料、傳送響應頭,傳送響應狀態碼的方法。
1.1.1 常用方法
- void setStatus(int sc); 設定此響應的狀態程式碼;
- void setHeader(String name, String value); 用給定名稱和值設定響應頭
1.2 響應行(狀態行)
1.2.1概述
- 響應行是http 響應內容的第一行
- 響應行分為三個部分:協議版本、響應狀態碼、對響應狀態碼的解釋
- 對於Tomcat,一般資料為:HTTP/1.1 200(tomcat8.5) 或者HTTP/1.1 200 OK(tomcat7)
1.2.2 常見的響應狀態碼
200 OK
:請求和響應都已成功,伺服器通訊正常;- 302 Move temporarily :設定重定向頁面跳轉的動作執行;
304 Not Modified
:從瀏覽器快取中讀取資料,不從伺服器重新獲取資料;404 Not Found
:請求失敗,請求所希望得到的資源未被在伺服器上發現。一般是使用者輸錯了url 導致;405 Method Not Allowed
:請求行中指定的請求方法不存在。例如,傳送post 請求,伺服器沒有doPost方法,就會報這個錯誤;500 Internal Server Error
: 伺服器發生了錯誤。一般伺服器程式碼錯誤。
1.3 響應頭
響應頭包含但不僅限於以下幾個屬性:
refresh
:定時重新整理跳轉頁面;location
:重定向操作:通常告知瀏覽器馬上向該地址傳送請求,通常和響應碼302 一起使用;content-encoding
:設定當前資料的壓縮格式,告知瀏覽器以何種壓縮格式解壓資料(目前瀏覽器只支援”gzip”格式解壓);content-disposition
:通知瀏覽器以何種方式獲取資料(直接解析資料(網頁,圖片文字),或者以附件方式(下載檔案));content-type
:實體頭部用於指示資源的MIME 型別。
注意:我們content-type 常用的設定一般都是“text/html;charset=utf-8”
其中“text/html;”——設定瀏覽器以檔案格式解析資料;“charset=utf-8”——響應資料的編碼表
1.3.1 響應頭:Location
- 作用:通知瀏覽器要進行頁面跳轉的目標地址
- http 狀態碼302 的作用是通知瀏覽器進行頁面跳轉的動作執行,所以響應頭location(跳轉目標地址)和http 狀態碼302 (跳轉動作執行)配合起來才可以完成頁面跳轉。
1.3.1.1 實現程式碼
方式一
//需求:跳轉到資源CountServlet
//設定跳轉目標地址
response.setHeader("location", "index.html");
//設定http狀態碼為302
response.setStatus(302);
優化程式碼(重要)
- response.sendRedirect("目標頁面/目標Servlet");
傳送重定向【原理就是方法一】
注意:目標頁面/Servlet需要寫工程名稱,但是不能將工程名寫死,需要用servletContext
來 獲取工程名字
1.3.1.2 請求轉發與請求重定向的區別及選擇(重點)
請求轉發的原理
請求重定向
總結(重要):
- 轉發在一次請求中完成,轉發位址列不變(只有一次請求);重定向則是兩次請求,重定向位址列變化(兩次請求,對應兩個地址);
- 轉發發生在伺服器內部,只能訪問伺服器當前工程的內部資源,不能訪問外部資源;重定向是瀏覽器執行跳轉操作,可以訪問任何資源;
- 轉發前後均共享同一個request和response(由伺服器收到第一次請求時建立);重定向前後有各自獨立的request和response;
- 一次請求建立一個request和response,在伺服器響應結束時就會銷燬。不同請求不會共享request和response。
選擇:
- 由於request 是請求域物件,如果頁面跳轉需要在一次請求域內傳遞資料的(即前後頁面要傳輸資料)使用請求轉發,否則建議使用重定向
注意事項:
- 重定向除了設定location實現之外,也能通過設定refresh實現。
1.3.2 響應頭:Content-Type
- 格式:
Content-Type: text/html; charset=碼錶
解釋:Content-Type是設定響應正文型別/報文型別,包含兩部分
第一部分:設定響應的資料型別(Mime-Type),伺服器
可以響應任何型別的資源給客戶端,資源不同,Mime-Type 不同。
Mime-Type | 含義 |
---|---|
text/html | Html 程式碼 |
text/plain | Txt 文字檔案 |
image/jpeg | Jpg 圖片檔案 |
Application/json | Json 資料 |
第二部分:響應字元碼錶:通知瀏覽器以什麼碼錶解碼資料
- 作用:用於伺服器通知瀏覽器採用什麼碼錶對伺服器響應的資料進行解碼。解決響應中文亂碼問題
1.3.2.1 獲取Mime-Type方法
- getServletContext().getMimeType(fileName)
根據Mime-Type設定檔案媒體格式
- 用來告知瀏覽器檔案的媒體格式,要根據哪種媒體格式解析資源
- response.setContentType(getServletContext().getMimeType(fileName));
1.3.2.2 伺服器端輸出中文資料有2 種方式
位元組流輸出
response.getOutputStream().write("輸出字串".getBytes());
字元流輸出
response.getWriter().write("輸出字串");
1.3.2.3 解決伺服器輸出字元流中文亂碼(重要)
- 產生亂碼原因:伺服器響應資料預設採用iso8859-1 碼錶,瀏覽器預設採用GBK碼錶。
瀏覽器與伺服器傳輸中文資料的url 編碼過程(瞭解)
- 對位元組陣列中的負數加256
- 將加後的位元組陣列轉換為十六進位制整型資料
- 之後在每個16 進位制資料前加%
解決方案:設定響應頭content-type
方案1:
//修改response預設輸出中文資料碼錶
response.setCharacterEncoding("utf-8");
//通知瀏覽器以utf-8 解碼
response.setHeader("content-type","text/html;charset=utf-8");
優化方案:
- response.setContentType("text/html;charset=utf8");
修改伺服器響應的編碼碼錶和瀏覽器解碼碼錶【原理就是方案1】
1.3.2.4 response輸出中文資料的區別
- 位元組流輸出中文不亂碼原因是中國編碼預設使用gbk,瀏覽器預設gbk解碼;
- 但由於有可能部分瀏覽器不適用gbk,用位元組流輸出中文資料不安全,故建議輸出中文資料使用字元流。
1.3.3 響應頭:refresh
-
格式:
Refresh: 定時時間;url=跳轉網址
- 定時時間:以秒為單位,不用引號;
- 跳轉網址:整個網頁的完整地址,不用引號;
-
作用:設定瀏覽器定時重新整理頁面或定時跳轉到指定的資源;
1.3.3.1 設定方式
/*需求:3 秒以後跳轉到demo.html*/
response.setHeader("refresh","3;url="+getServletContext().getContextPath()+"/demo.html");
- 注意,工程名不能寫死
1.3.3.2 重新整理和跳轉案例
@WebServlet(urlPatterns = "/demo01")
public class Notes01Servlet extends HttpServlet {
/*
需求:倒計時5秒後跳轉到新的頁面succeed.html。
思路:首先直接進入demo01(Servlet),然後進入到倒計時的wait.html,5秒後跳轉到新的頁面
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//5秒後跳轉到新的頁面中,使用refresh重定向跳轉
//這裡修改第一次進入demo01時建立的response物件refresh屬性實現跳轉功能
response.setHeader("refresh", "2;url=succeed.html");
//1.這裡必須使用請求轉發頁面跳轉
//2.如果這裡也使用重定向,那麼重定向後上面修改refresh的response已經被銷燬而建立了新的response,自然無法跳轉
//3.上一行程式碼和這行程式碼的順序不能調,因為本行程式碼已經將request和response轉發了,那麼就沒有response能呼叫上行程式碼
request.getRequestDispatcher("/wait.html").forward(request, response);
/*
response.sendRedirect("/day29/wait.html"); //跳轉後此時傳入的response已經被銷燬
response.setHeader("refresh", "2;url=succeed.html"); //這裡的response仍是傳入的response,已被銷燬,該行程式碼無效,也不會修改到跳轉後的refresh實現再度跳轉
//上述兩行程式碼也說明,即使是先重定向到wait.html,再refresh也無法跳轉
*/
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//*如果post方式的執行內容與get不同,則刪掉下面程式碼重寫即可
doGet(request, response);
}
}
1.3.4 響應頭:Content-Disposition
-
格式:
Content-Disposition: attachment; filename=下載檔名
- attachment,通知瀏覽器不要顯示資料要以附件形式下載
- 下載檔名:下載的檔名字,包含字尾名
-
作用:預設瀏覽器檢視資料是直接顯示資料,而Content-Disposition可以通知瀏覽器不要直接顯示資料,以附件形式下載資料
1.3.4.1 設定方式
response.setHeader("content-disposition","attachment;filename="+fileName);
1.3.4.2 注意事項
- 如果響應頭傳遞中文預設不會進行url編碼,故無法傳遞中文,需要手動進行url編碼;
- 請求體和請求行、響應體在傳遞中文資料會自動進行url編碼;
- 瀏覽器和伺服器在傳輸中文資料時,中間過程還要進行url編碼,才能執行中文資料傳輸。
手動進行URL編碼的程式碼(不需強記,直接複製即可)
String fileName = "檔名.字尾名";
String ua = request.getHeader("User-Agent");
boolean IE_LT11 = ua.contains("MSIE"); // IE11 以下版本
boolean IE11 = ua.contains("rv:11.0) like Gecko"); // IE11
boolean Edge = ua.contains("Edge"); // win10 自帶的Edge 瀏覽器
// 如果是微軟的瀏覽器,直接進行UTF-8 編碼
if (IE_LT11 || IE11 || Edge) {
fileName = URLEncoder.encode(fileName, "UTF-8");
// java 的編碼方式和瀏覽器有略微的不同:對於空格,java 編碼後的結果是加號,
// 而瀏覽器的編碼結果是%20,因此將+替換成%20, 這樣瀏覽器才能正確解析空格
fileName = fileName.replace("+", "%20");
}
// 標準瀏覽器使用Base64 編碼
else {
Base64.Encoder encoder = Base64.getEncoder();
fileName = encoder.encodeToString(fileName.getBytes("utf-8"));
// =?utf-8?B?檔名?= 是告訴瀏覽器以Base64 進行解碼
fileName = "=?utf-8?B?" + fileName + "?=";
}
1.3.4.3 擴充套件案例:以附件形式下載不同型別檔案(類似於工具類)
前期準備:download頁面由前端編寫,這裡只是簡單的頁面。
另外還要注意,本地可訪問資源要放在IDEA的web資料夾內
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下載頁面</title>
<style type="text/css"></style>
<script type="text/javascript">
/*
除了IE瀏覽器(IE11及以下)預設不對路徑中的中文字元進行編碼以外,其餘瀏覽器都會支援中文路徑編碼,
所以為了傳送請求時解決中文亂碼的問題,這裡要對瀏覽器進行判斷。如果是ie11及以下的要手動url編碼
*/
function isIE() {
//獲取當前瀏覽器相關資訊
var explorer = window.navigator.userAgent.toLowerCase();
//判斷是否是ie瀏覽器
if (explorer.indexOf("msie") >= 0 || explorer.indexOf("rv:11.0) like gecko") >= 0) {
return true;
} else {
false;
}
}
window.onload = function () {
if (isIE()) {
//在是IE瀏覽器的情況下,對中文請求引數編碼
var str = document.getElementById("sn").href;
var str = encodeURI(str);
document.getElementById("sn").href = str;
}
};
</script>
</head>
<body>
<a href="download?fileName=1.txt">1.txt</a> <!--路徑預設使用get方式提交,用?串聯相當於提交該檔案-->
<a href="download?fileName=Impactor_0.9.34.zip">Impactor_0.9.34.zip</a>
<a href="download?fileName=hq.jpg">hq.jpg</a>
<a id="sn" href="download?fileName=燒酒.png">燒酒.png</a>
</body>
</html>
後端程式碼
注意:如果檔名有中文和特殊字元,必須要先解決request的中文亂碼問題,否則獲取的檔名亂碼,導致對應的資源無法下載
@WebServlet(urlPatterns = "/download")
public class Notes02DownloadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解決request中文亂碼問題
request.setCharacterEncoding("utf-8");
/*1.獲得下載的檔名字*/
String fileName = request.getParameter("fileName");
System.out.println(fileName);
/*2.獲取資源的真實路徑*/
ServletContext servletContext = getServletContext();
String realPath = servletContext.getRealPath("/download");
//根據真實路徑獲得file物件,用來建立輸入流,讀取檔案
File file = new File(realPath,fileName);
/*3.根據Mime-Type設定檔案媒體格式,告知瀏覽器傳輸的檔案是什麼格式*/
response.setContentType(servletContext.getMimeType(fileName));
/*4.解決中文檔名亂碼的問題,複製黏貼即可*/
String ua = request.getHeader("User-Agent");
boolean IE_LT11 = ua.contains("MSIE"); // IE11以下版本
boolean IE11 = ua.contains("rv:11.0) like Gecko"); // IE11
boolean Edge = ua.contains("Edge"); // win10自帶的Edge瀏覽器
// 如果是微軟的瀏覽器,直接進行UTF-8編碼
if (IE_LT11 || IE11 || Edge) {
fileName = URLEncoder.encode(fileName, "UTF-8");
// java的編碼方式和瀏覽器有略微的不同:對於空格,java編碼後的結果是加號,
// 而瀏覽器的編碼結果是%20,因此將+替換成%20, 這樣瀏覽器才能正確解析空格
fileName = fileName.replace("+", "%20");
}
// 標準瀏覽器使用Base64編碼
else {
Base64.Encoder encoder = Base64.getEncoder();
fileName = encoder.encodeToString(fileName.getBytes("utf-8"));
// =?utf-8?B?檔名?= 是告訴瀏覽器以Base64進行解碼
fileName = "=?utf-8?B?" + fileName + "?=";
}
/*5.提示瀏覽器以下載的形式獲取伺服器資源*/
response.setHeader("content-disposition","attachment;filename=" + fileName);
/*6.使用流輸出資料*/
FileInputStream fis = new FileInputStream(file);
ServletOutputStream sos = response.getOutputStream();
byte[] bytes = new byte[1024];
int len = -1;
while ((len = fis.read(bytes))!= -1) {
sos.write(bytes,0,len);
}
/*7.記得關閉輸入流釋放資源*/
fis.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//*如果post方式的執行內容與get不同,則刪掉下面程式碼重寫即可
doGet(request, response);
}
}
1.4 響應體
- 瀏覽器將伺服器輸出的資料直接顯示給使用者
- 作用:
- 輸出字元資料、位元組資料
- 輸出資原始檔資料(資源圖片)
- 輸出快取(記憶體中)圖片(資源沒有對應的物理資源,不是真實資源)–驗證碼
1.4.1 驗證碼案例(類似工具類)
實現驗證碼功能
@WebServlet(urlPatterns = "/CheckCodeServlet")
public class Notes03CheckCodeServlet extends HttpServlet {
//獲取隨機數
private Random random = new Random();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//建立一個快取圖片
//BufferedImage(int width,int height,int imageType)
BufferedImage image = new BufferedImage(90,30,BufferedImage.TYPE_INT_RGB);
//獲取畫筆
Graphics g = image.getGraphics();
//設定畫筆的顏色
g.setColor(Color.white);
//設定畫布範圍
g.fillRect(0,0,90,30);
//畫干擾線
//g.drawLine(x1,y1,x2,y2);
for (int i=1;i<=4;i++){
//設定每條線的隨機顏色
g.setColor(getColor());
int x1=random.nextInt(91);
int y1=random.nextInt(31);
int x2=random.nextInt(91);
int y2=random.nextInt(31);
g.drawLine(x1,y1,x2,y2);
}
//畫驗證碼
String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890小天使";
//隨機選取4個
StringBuilder checkCode = new StringBuilder();
for(int i=0;i<4;i++){
int index = random.nextInt(data.length());
char item = data.charAt(index);
checkCode.append(item);
}
System.out.println("驗證碼:"+checkCode.toString());
//將驗證碼畫到圖片上
//g.drawString(str,x,y);
int i=0;
for(char item : checkCode.toString().toCharArray()){
//設定每個字元隨機顏色
g.setColor(getColor());
//將每個字元畫到圖片上
g.drawString(item+"",10+(i*20),15);
i++;
}
//將記憶體圖片輸出到瀏覽器中
ImageIO.write(image,"png",response.getOutputStream());
}
/*獲取隨機顏色*/
public Color getColor(){
int r = random.nextInt(256);
int g = random.nextInt(256);
int b = random.nextInt(256);
//Color(int r, int g, int b)
return new Color(r,g,b);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//*如果post方式的執行內容與get不同,則刪掉下面程式碼重寫即可
doGet(request, response);
}
}
2. ServletContext
2.1 ServletContext概述
1、ServletContext 是一個容器(**域物件**)可以儲存**鍵值對資料(String key,Object value)**,儲存在ServletContext 中的資料不僅可以**提供給所有的servlet 使用**,而且可以在**整個專案範圍內使用**(後期的過濾器、監聽器也可以使用ServletContext)
2、伺服器會為每一個工程建立一個ServletContext 物件,這個物件就是ServletContext 物件。這個物件**全域性唯一(一個工程僅一個)**,而且**工程內部的所有servlet 都共享**這個物件。所以叫**全域性應用程式共享物件**。
3、伺服器啟動就建立ServletContext,伺服器關閉了才銷燬ServletContext
2.2 ServletContext的作用
- 可以讀取資源在當前專案中的檔案位置;
- 可以作為域物件在專案全域性範圍內提供共享資料。
2.3 使用ServletContext讀取資源在當前專案中的檔案位置
-
方法:
- String getServletContext().getRealPath(path); 根據相對路徑獲取專案部署位置上資源的絕對路徑
2.3.1 示例程式碼
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
//servletContext可以獲取當前專案下的資原始檔
//可以根據相對路徑獲取在伺服器上的絕對路徑
String realPath =
相關推薦
no