其餘更多java基礎文章: java基礎學習(目錄)html
學習request和response以前先學習一下http請求java
瀏覽器向服務器請求某個web資源時,稱之爲瀏覽器向服務器發送了一個http請求。一個完整http請求應該包含三個部分:web
請求行:GET /java.html HTTP/1.1 請求行中的GET稱之爲請求方式,
請求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT。
經常使用的有:POST,GET
通常來講,當咱們點擊超連接,經過地址欄訪問都是get請求方式。經過表單提交的數據通常是post方式。
能夠簡單理解GET方式用來查詢數據,POST方式用來提交數據,get的提交速度比post快
GET方式:在URL地址後附帶的參數是有限制的,其數據容量一般不能超過1K。
POST方式:能夠在請求的實體內容中向服務器發送數據,傳送的數據量無限制。apache
一個HTTP響應表明着服務器向瀏覽器回送數據,一個完整的HTTP響應應該包含四個部分:編程
格式: HTTP版本號 狀態碼 緣由敘述 狀態行:HTTP/1.1 200 OK 狀態碼用於表示服務器對請求的處理結果,它是一個三位的十進制數。響應狀態碼分爲5類json
HttpServletRequest對象表明客戶端的請求,當客戶端經過HTTP協議訪問服務器時,HTTP請求頭中的全部信息都封裝在這個對象中,開發人員經過這個對象的方法,能夠得到客戶這些信息。 request就是將請求文本封裝而成的對象,因此經過request能得到請求文本中的全部內容,請求頭、請求體、請求行 數組
咱們能夠查看任意一個網頁,它都是有請求頭的。瀏覽器
相關方法:
String getHeader(String name) 根據頭名稱獲得頭信息值
long getDateHeader(java.lang.String name) 得到指定頭內容Date
int getIntHeader(java.lang.String name) 得到指定頭內容int
Enumeration getHeaderNames() 獲得全部頭信息name
Enumeration getHeaders(String name) 根據頭名稱獲得相同名稱頭信息值緩存
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String key = (String)headerNames.nextElement();
String value = req.getHeader(key);
System.out.println(key+"="+value);
}
複製代碼
1)與表單獲取相關的方法:
String getParameter(name) :根據表單中name屬性的名,獲取value屬性的值方法
String[] getParameterValues(String name):專爲複選框取取提供的方法
getParameterNames():獲得表單提交的全部name的方法
Map<String , String[]> getParameterMap(): 獲得表單提交的全部值的方法 //作框架用,很是實用
getInputStream: 以字節流的方式獲得全部表單數據tomcat
2)與操做非表單數據相關的方法(request也是一個域對象):
void setAttribute(String name, Object value);
Object getAttribute(String name);
Void removeAttribute(String name);
3)與請求轉發相關的方法:
RequestDispatcher getRequestDispatcher(String path) //獲得請求轉發或請求包含的協助對象
forward(ServletRequest request, ServletResponse response) //轉發的方法
include(ServletRequest request, ServletResponse response) //請求包含
4)與編碼相關的方法:
//解決post方式編碼
request.setCharacterEncoding("UTF-8") :告訴服務器客戶端什麼編碼,只能處理post請求方式
//解決get方式編碼
String name = new String(name.getBytes(「iso-8859-1」),」UTF-8」);
#####3. 其餘經常使用請求方法
getMethod();
getRequestURL();
getRequestURI();
getServerName();
getServerPort();
getContextPath();
getServletPath();
getQueryString();
getRemoteAddr();
getProtocol();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.統一資源標記符 /Web_Servlet/ServletTest3
String uri = req.getRequestURI();
System.out.println(uri);
//2.統一資源定位符 http://localhost:6060/Web_Servlet/ServletTest3
StringBuffer url = req.getRequestURL();
System.out.println(url);
//3.協議和版本 HTTP/1.1
String potocol = req.getProtocol();
System.out.println(potocol);
//4.協議 http
String scheme = req.getScheme();
System.out.println(scheme);
//5.主機(域名) localhost,若是你使用的是ip地址,就顯示ip地址
String serverName = req.getServerName();
System.out.println(serverName);
//6.端口 6060(這是我本身修改了的端口,默認是8080)
int port = req. getServerPort();
System.out.println(port);
//7.發佈到tomcat下的項目名稱 /Web_Servlet
String contextPath = req.getContextPath();
System.out.println(contextPath);
//8.servlet路徑 /ServletTest3
String servletPath = req.getServletPath();
System.out.println(servletPath);
//9.獲取全部請求參數,即?以後全部東西。 username=faker&password=mid
String queryString = req.getQueryString();
System.out.println(queryString);
//10.遠程主機的ip地址 0:0:0:0:0:0:0:1
String remoteAddr = req.getRemoteAddr();
System.out.println(remoteAddr);
}
複製代碼
Web服務器收到客戶端的http請求,會針對每一次請求,分別建立一個用於表明請求的request對象、和表明響應的response對象。request和response對象即然表明請求和響應,那咱們要獲取客戶機提交過來的數據,只須要找request對象就好了。要向容器輸出數據,只須要找response對象就好了。
HttpServletResponse對象表明服務器的響應。這個對象中封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法。
setStatus(int sc) 設置響應狀態碼
setHeader(String name, String value) 設置響應頭信息
getWrite(); 字符輸出流
getOutputStream(); 字節輸出流
setCharacterEncoding(String charset) 告知服務器使用什麼編碼
setContentType(String type) 告訴響應的內容類型(text/html,application/json等)
response.sendRedirect(path);
注意:重定向沒有任何侷限,能夠重定向web項目內的任何路徑,也能夠訪問別的web項目中的路徑,而且這裏就用"/"區分開來,若是path使用了"/"開頭,就說明我要從新開始定位了,不訪問剛纔的web項目,本身寫項目名,若是path沒有使用"/"開始,那麼就知道是訪問剛纔那個web項目下的servlet,就能夠省略項目名了。就是這樣來區別。
request.setCharacterEncoding()指定後能夠經過getParameter()則直接得到正確的字符串,若是不指定,則默認使用iso8859-1編碼。值得注意的是在執行setCharacterEncoding()以前,不能執行任何getParameter()。並且,該指定只對POST方法有效,對GET方法無效。
分析緣由,應該是在執行第一個getParameter()的時候,Java將會按照編碼分析全部的提交內容,然後續的getParameter()再也不進行分析,因此setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析提交內容,setCharacterEncoding()天然就無效。
response.setCharacterEncoding設置HTTP 響應的編碼,若是以前使用response.setContentType設置了編碼格式,則使用response.setCharacterEncoding指定的編碼格式覆蓋以前的設置.與response.setContentType相同的是,調用此方法,必須在getWriter執行以前或者response被提交以前
轉發是發生在服務器的:
轉發是由服務器進行跳轉的,細心的朋友會發現,在轉發的時候,瀏覽器的地址欄是沒有發生變化的,在我訪問Servlet111的時候,即便跳轉到了Servlet222的頁面,瀏覽器的地址仍是Servlet111的。也就是說瀏覽器是不知道該跳轉的動做,轉發是對瀏覽器透明的。經過上面的轉發時序圖咱們也能夠發現,實現轉發只是一次的http請求,一次轉發中request和response對象都是同一個。這也解釋了,爲何可使用request做爲域對象進行Servlet之間的通信。
重定向是發生在瀏覽器的:
重定向是由瀏覽器進行跳轉的,進行重定向跳轉的時候,瀏覽器的地址會發生變化的。曾經介紹過:實現重定向的原理是由response的狀態碼和Location頭組合而實現的。這是由瀏覽器進行的頁面跳轉實現重定向會發出兩個http請求,request域對象是無效的,由於它不是同一個request對象
不少人都搞不清楚轉發和重定向的時候,資源地址究竟怎麼寫。有的時候要把應用名寫上,有的時候不用把應用名寫上。很容易把人搞暈。記住一個原則:給服務器用的直接從資源名開始寫,給瀏覽器用的要把應用名寫上
request.getRequestDispatcher("/資源名 URI").forward(request,response)
轉發時"/"表明的是本應用程序的根目錄
response.send("/web應用/資源名 URI");
重定向時"/"表明的是webapps目錄
轉發是服務器跳轉只能去往當前web應用的資源
重定向是服務器跳轉,能夠去往任何的資源
轉發的request對象能夠傳遞各類類型的數據,包括對象
重定向只能傳遞字符串
轉發時:執行到跳轉語句時就會馬上跳轉
重定向:整個頁面執行完以後才執行跳轉
PrintWriter對象輸出字符文本內容時,它內部仍是將字符串轉換成了某種字符集編碼的字節數組後再進行輸出,使用PrintWriter對象的好處就是不用編程人員本身來完成字符串到字節數組的轉換。
使用ServletOutputStream對象也能輸出內容全爲文本字符的網頁文檔,可是,若是網頁文檔內容是在Servlet程序內部使用文本字符串動態拼湊和建立出來的,則須要先將字符文本轉換成字節數組後輸出。
getOutputStream方法用於返回Servlet引擎建立的字節輸出流對象,Servlet程序能夠按字節形式輸出響應正文。
getWriter方法用於返回Servlet引擎建立的字符輸出流對象,Servlet程序能夠按字符形式輸出響應正文。
getOutputStream和getWriter這兩個方法互相排斥,調用了其中的任何一個方法後,就不能再調用另外一方法。
getOutputStream方法返回的字節輸出流對象的類型爲ServletOutputStream,它能夠直接輸出字節數組中的二進制數據。
getWriter方法將Servlet引擎的數據緩衝區包裝成PrintWriter類型的字符輸出流對象後返回,PrintWriter對象能夠直接輸出字符文本內容。
Servlet程序向ServletOutputStream或PrintWriter對象中寫入的數據將被Servlet引擎獲取,Servlet引擎將這些數據看成響應消息的正文,而後再與響應狀態行和各響應頭組合後輸出到客戶端。
Serlvet的service方法結束後,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流對象是否已經調用過close方法,若是沒有,Servlet引擎將調用close方法關閉該輸出流對象。
getOutputStream解決辦法:
rgetWriter解決辦法:
response. setContentType(「text/html;charset=UTF-8」);
//經過路徑獲得一個輸入流
String path = this.getServletContext().getRealPath(filepath);
FileInputStream fis = new FileInputStream(path);
//建立字節輸出流
ServletOutputStream sos = response.getOutputStream();
//獲得要下載的文件名
String filename = path.substring(path.lastIndexOf("\\")+1);
//設置文件名的編碼
filename = URLEncoder.encode(filename, "UTF-8");//將不安全的文件名改成UTF-8格式
//告知客戶端要下載文件
response.setHeader("content-disposition", "attachment;filename="+filename);
response.setHeader("content-type", "image/jpeg");
//執行輸出操做
int len = 1;
byte[] b = new byte[1024];
while((len=fis.read(b))!=-1){
sos.write(b,0,len);
}
sos.close();
fis.close();
複製代碼
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("3秒後跳轉頁面.....");
//三秒後跳轉到index.jsp頁面去
response.setHeader("Refresh", "3;url='/index.jsp'");
複製代碼
//瀏覽器有三消息頭設置緩存,爲了兼容性!將三個消息頭都設置了
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma", "no-cache");
複製代碼
//建立GZIPOutputStream對象,給予它ByteArrayOutputStream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
//GZIP對數據壓縮,GZIP寫入的數據是保存在byteArrayOutputStream上的
gzipOutputStream.write("asdfzxcvasdfzxvasdfzxcv".getBytes());
//gzipOutputStream有緩衝,把緩衝清了,並順便關閉流
gzipOutputStream.close();
byte[] bytes = byteArrayOutputStream.toByteArray();
//告訴瀏覽器這是gzip壓縮的數據
response.setHeader("Content-Encoding","gzip");
//將壓縮的數據寫給瀏覽器
response.getOutputStream().write(bytes);
複製代碼
//獲取到網頁是從哪裏來的
String referer = request.getHeader("Referer");
複製代碼