請求響應流程圖
response
response概述
response是Servlet.service方法的一個參數,類型為javax.servlet.http.HttpServletResponse。在用戶端發出每個請求時,伺服器都會建立一個response對象,并傳入給Servlet.service()方法。response對象是用來對用戶端進行響應的,這說明在service()方法中使用response對象可以完成對用戶端的響應工作。
response對象的功能分為以下四種:
設定響應頭資訊;
發送狀态碼;
設定響應正文;
重定向;
2 response響應正文
response是響應對象,向用戶端輸出響應正文(響應體)可以使用response的響應流,repsonse一共提供了兩個響應流對象:
PrintWriter out = response.getWriter():擷取字元流;
ServletOutputStream out = response.getOutputStream():擷取位元組流;
當然,如果響應正文内容為字元,那麼使用response.getWriter(),如果響應内容是位元組,例如下載下傳時,那麼可以使用response.getOutputStream()。
注意,在一個請求中,不能同時使用這兩個流!也就是說,要麼你使用repsonse.getWriter(),要麼使用response.getOutputStream(),但不能同時使用這兩個流。不然會抛出IllegalStateException異常。
2.1 字元響應流
字元編碼
在使用response.getWriter()時需要注意預設字元編碼為ISO-8859-1,如果希望設定字元流的字元編碼為utf-8,可以使用response.setCharaceterEncoding(“utf-8”)來設定。這樣可以保證輸出給用戶端的字元都是使用UTF-8編碼的!
但用戶端浏覽器并不知道響應資料是什麼編碼的!如果希望通知用戶端使用UTF-8來解讀響應資料,那麼還是使用response.setContentType("text/html;charset=utf-8")方法比較好,因為這個方法不隻會調用response.setCharaceterEncoding(“utf-8”),還會設定content-type響應頭,用戶端浏覽器會使用content-type頭來解讀響應資料。
緩沖區
response.getWriter()是PrintWriter類型,是以它有緩沖區,緩沖區的預設大小為8KB。也就是說,在響應資料沒有輸出8KB之前,資料都是存放在緩沖區中,而不會立刻發送到用戶端。當Servlet執行結束後,伺服器才會去重新整理流,使緩沖區中的資料發送到用戶端。
如果希望響應資料馬上發送給用戶端:
向流中寫入大于8KB的資料;
調用response.flushBuffer()方法來手動重新整理緩沖區;
3 設定響應頭資訊
可以使用response對象的setHeader()方法來設定響應頭!使用該方法設定的響應頭最終會發送給用戶端浏覽器!
response.setHeader(“content-type”, “text/html;charset=utf-8”):設定content-type響應頭,該頭的作用是告訴浏覽器響應内容為html類型,編碼為utf-8。而且同時會設定response的字元流編碼為utf-8,即response.setCharaceterEncoding(“utf-8”);
response.setHeader("Refresh","5; URL=http://www.itcast.cn"):5秒後自動跳轉到智首頁。
4 設定狀态碼及其他方法
response.setContentType("text/html;charset=utf-8"):等同與調用response.setHeader(“content-type”, “text/html;charset=utf-8”);
response.setCharacterEncoding(“utf-8”):設定字元響應流的字元編碼為utf-8;
response.setStatus(200):設定狀态碼;
response.sendError(404, “您要查找的資源不存在”):當發送錯誤狀态碼時,Tomcat會跳轉到固定的錯誤頁面去,但可以顯示錯誤資訊。
5 重定向
5.1 什麼是重定向
當你通路http://www.sun.com時,你會發現浏覽器位址欄中的URL會變成http://www.oracle.com/us/sun/index.htm,這就是重定向了。
重定向是伺服器通知浏覽器去通路另一個位址,即再發出另一個請求。
5.2 完成重定向
響應碼為200表示響應成功,而響應碼為302表示重定向。是以完成重定向的第一步就是設定響應碼為302。
因為重定向是通知浏覽器再第二個請求,是以浏覽器需要知道第二個請求的URL,是以完成重定向的第二步是設定Location頭,指定第二個請求的URL位址。
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(302);
response.setHeader("Location", "http://www.baidu.com");
}
}
上面代碼的作用是:當通路AServlet後,會通知浏覽器重定向到智首頁。用戶端浏覽器解析到響應碼為302後,就知道伺服器讓它重定向,是以它會馬上擷取響應頭Location,然發出第二個請求。
5.3 便捷的重定向方式
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("http://www.baidu.com");
}
}
response.sendRedirect()方法會設定響應頭為302,以設定Location響應頭。
如果要重定向的URL是在同一個伺服器内,那麼可以使用相對路徑,例如:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("/hello/BServlet");
}
}
重定向的URL位址為:http://localhost:8080/hello/BServlet。
5.4 重定向小結
重定向是兩次請求;
重定向的URL可以是其他應用,不局限于目前應用;
重定向的響應頭為302,并且必須要有Location響應頭;
重定向就不要再使用response.getWriter()或response.getOutputStream()輸出資料,不然可能會出現異常;
request
1 request概述
request是Servlet.service()方法的一個參數,類型為javax.servlet.http.HttpServletRequest。在用戶端發出每個請求時,伺服器都會建立一個request對象,并把請求資料封裝到request中,然後在調用Servlet.service()方法時傳遞給service()方法,這說明在service()方法中可以通過request對象來擷取請求資料。
request的功能可以分為以下幾種:
封裝了請求頭資料;
封裝了請求正文資料,如果是GET請求,那麼就沒有正文;
request是一個域對象,可以把它當成Map來添加擷取資料;
request提供了請求轉發和請求包含功能。
2 request域方法
request是域對象!在JavaWeb中一共四個域對象,其中ServletContext就是域對象,它在整個應用中隻建立一個ServletContext對象。request其中一個,request可以在一個請求中共享資料。
一個請求會建立一個request對象,如果在一個請求中經曆了多個Servlet,那麼多個Servlet就可以使用request來共享資料。現在我們還不知道如何在一個請求中經曆之個Servlet,後面在學習請求轉發和請求包含後就知道了。
下面是request的域方法:
void setAttribute(String name, Object value):用來存儲一個對象,也可以稱之為存儲一個域屬性,例如:servletContext.setAttribute(“xxx”, “XXX”),在request中儲存了一個域屬性,域屬性名稱為xxx,域屬性的值為XXX。請注意,如果多次調用該方法,并且使用相同的name,那麼會覆寫上一次的值,這一特性與Map相同;
Object getAttribute(String name):用來擷取request中的資料,目前在擷取之前需要先去存儲才行,例如:String value = (String)request.getAttribute(“xxx”);,擷取名為xxx的域屬性;
void removeAttribute(String name):用來移除request中的域屬性,如果參數name指定的域屬性不存在,那麼本方法什麼都不做;
Enumeration getAttributeNames():擷取所有域屬性的名稱;
3 request擷取請求頭資料
request與請求頭相關的方法有:
String getHeader(String name):擷取指定名稱的請求頭;
Enumeration getHeaderNames():擷取所有請求頭名稱;
int getIntHeader(String name):擷取值為int類型的請求頭。
4 request擷取請求相關的其它方法
request中還提供了與請求相關的其他方法,有些方法是為了我們更加便捷的方法請求頭資料而設計,有些是與請求URL相關的方法。
int getContentLength():擷取請求體的位元組數,GET請求沒有請求體,沒有請求體傳回-1;
String getContentType():擷取請求類型,如果請求是GET,那麼這個方法傳回null;如果是POST請求,那麼預設為application/x-www-form-urlencoded,表示請求體内容使用了URL編碼;
String getMethod():傳回請求方法,例如:GET
Locale getLocale():傳回目前用戶端浏覽器的Locale。java.util.Locale表示國家和言語,這個東西在國際化中很有用;
String getCharacterEncoding():擷取請求編碼,如果沒有setCharacterEncoding(),那麼傳回null,表示使用ISO-8859-1編碼;
void setCharacterEncoding(String code):設定請求編碼,隻對請求體有效!注意,對于GET而言,沒有請求體!!!是以此方法隻能對POST請求中的參數有效!
String getContextPath():傳回上下文路徑,例如:/hello
String getQueryString():傳回請求URL中的參數,例如:name=zhangSan
String getRequestURI():傳回請求URI路徑,例如:/hello/oneServlet
StringBuffer getRequestURL():傳回請求URL路徑,例如:http://localhost/hello/oneServlet,即傳回除了參數以外的路徑資訊;
String getServletPath():傳回Servlet路徑,例如:/oneServlet
String getRemoteAddr():傳回目前用戶端的IP位址;
String getRemoteHost():傳回目前用戶端的主機名,但這個方法的實作還是擷取IP位址;
String getScheme():傳回請求協定,例如:http;
String getServerName():傳回主機名,例如:localhost
int getServerPort():傳回伺服器端口号,例如:8080
System.out.println("request.getContentLength(): " + request.getContentLength());
System.out.println("request.getContentType(): " + request.getContentType());
System.out.println("request.getContextPath(): " + request.getContextPath());
System.out.println("request.getMethod(): " + request.getMethod());
System.out.println("request.getLocale(): " + request.getLocale());
System.out.println("request.getQueryString(): " + request.getQueryString());
System.out.println("request.getRequestURI(): " + request.getRequestURI());
System.out.println("request.getRequestURL(): " + request.getRequestURL());
System.out.println("request.getServletPath(): " + request.getServletPath());
System.out.println("request.getRemoteAddr(): " + request.getRemoteAddr());
System.out.println("request.getRemoteHost(): " + request.getRemoteHost());
System.out.println("request.getRemotePort(): " + request.getRemotePort());
System.out.println("request.getScheme(): " + request.getScheme());
System.out.println("request.getServerName(): " + request.getServerName());
System.out.println("request.getServerPort(): " + request.getServerPort());
4.1 案例:request.getRemoteAddr():封IP
可以使用request.getRemoteAddr()方法擷取用戶端的IP位址,然後判斷IP是否為禁用IP。
String ip = request.getRemoteAddr();
System.out.println(ip);
if(ip.equals("127.0.0.1")) {
response. getWriter().print("您的IP已被禁止!");
} else {
response.getWriter().print("Hello!");
}
5 request擷取請求參數
最為常見的用戶端傳遞參數方式有兩種:
浏覽器位址欄直接輸入:一定是GET請求;
超連結:一定是GET請求;
表單:可以是GET,也可以是POST,這取決與<form>的method屬性值;
GET請求和POST請求的差別:
GET請求:
請求參數會在浏覽器的位址欄中顯示,是以不安全;
請求參數長度限制長度在1K之内;
GET請求沒有請求體,無法通過request.setCharacterEncoding()來設定參數的編碼;
POST請求:
請求參數不會顯示浏覽器的位址欄,相對安全;
請求參數長度沒有限制;
<a href="/hello/ParamServlet?p1=v1&p2=v2">超連結</a>
<hr/>
<form action="/hello/ParamServlet" method="post">
參數1:<input type="text" name="p1"/><br/>
參數2:<input type="text" name="p2"/><br/>
<input type="submit" value="送出"/>
</form>
下面是使用request擷取請求參數的API:
String getParameter(String name):通過指定名稱擷取參數值;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String v1 = request.getParameter("p1");
String v2 = request.getParameter("p2");
System.out.println("p1=" + v1);
System.out.println("p2=" + v2);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String v1 = request.getParameter("p1");
String v2 = request.getParameter("p2");
System.out.println("p1=" + v1);
System.out.println("p2=" + v2);
}
String[] getParameterValues(String name):當多個參數名稱相同時,可以使用方法來擷取;
<a href="/hello/ParamServlet?name=zhangSan&name=liSi">超連結</a>
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String[] names = request.getParameterValues("name");
System.out.println(Arrays.toString(names));
}
Enumeration getParameterNames():擷取所有參數的名字;
<form action="/hello/ParamServlet" method="post">
參數1:<input type="text" name="p1"/><br/>
參數2:<input type="text" name="p2"/><br/>
<input type="submit" value="送出"/>
</form>
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Enumeration names = request.getParameterNames();
while(names.hasMoreElements()) {
System.out.println(names.nextElement());
}
}
Map getParameterMap():擷取所有參數封裝到Map中,其中key為參數名,value為參數值,因為一個參數名稱可能有多個值,是以參數值是String[],而不是String。
<a href="/day05_1/ParamServlet?p1=v1&p1=vv1&p2=v2&p2=vv2">超連結</a>
Map<String,String[]> paramMap = request.getParameterMap();
for(String name : paramMap.keySet()) {
String[] values = paramMap.get(name);
System.out.println(name + ": " + Arrays.toString(values));
}
p2: [v2, vv2]
p1: [v1, vv1]
6 請求轉發和請求包含
無論是請求轉發還是請求包含,都表示由多個Servlet共同來處理一個請求。例如Servlet1來處理請求,然後Servlet1又轉發給Servlet2來繼續處理這個請求。
6.1 請求轉發
在AServlet中,把請求轉發到BServlet:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("AServlet");
RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
rd.forward(request, response);
}
}
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("BServlet");
}
}
Aservlet
BServlet
6.2 請求包含
在AServlet中,把請求包含到BServlet:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("AServlet");
RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
rd.include(request, response);
}
}
public class BServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("BServlet");
}
}
Aservlet
BServlet
6.3 請求轉發與請求包含比較
如果在AServlet中請求轉發到BServlet,那麼在AServlet中就不允許再輸出響應體,即不能再使用response.getWriter()和response.getOutputStream()向用戶端輸出,這一工作應該由BServlet來完成;如果是使用請求包含,那麼沒有這個限制;
請求轉發雖然不能輸出響應體,但還是可以設定響應頭的,例如:response.setContentType(”text/html;charset=utf-8”);
請求包含大多是應用在JSP頁面中,完成多頁面的合并;
請求請求大多是應用在Servlet中,轉發目标大多是JSP頁面;
6.4 請求轉發與重定向比較
請求轉發是一個請求,而重定向是兩個請求;
請求轉發後浏覽器位址欄不會有變化,而重定向會有變化,因為重定向是兩個請求;
請求轉發的目标隻能是本應用中的資源,重定向的目标可以是其他應用;
請求轉發對AServlet和BServlet的請求方法是相同的,即要麼都是GET,要麼都是POST,因為請求轉發是一個請求;
重定向的第二個請求一定是GET;
路徑
1 與路徑相關的操作
超連結
表單
轉發
包含
重定向
<url-pattern>
ServletContext擷取資源
Class擷取資源
ClassLoader擷取資源
2 用戶端路徑
超連結、表單、重定向都是用戶端路徑,用戶端路徑可以分為三種方式:
絕對路徑;
以“/”開頭的相對路徑;
不以“/”開頭的相對路徑;
例如:http://localhost:8080/hello1/pages/a.html中的超連結和表單如下:
絕對路徑:<a href="http://localhost:8080/hello2/index.html">連結1</a>
用戶端路徑:<a href="/hello3/pages/index.html">連結2</a>
相對路徑:<a href="index.html">連結3</a>
<hr/>
絕對路徑:
<form action="http://localhost:8080/hello2/index.html">
<input type="submit" value="表單1"/>
</form>
用戶端路徑:
<form action="/hello2/index.html">
<input type="submit" value="表單2"/>
</form>
相對路徑:
<form action="index.html">
<input type="submit" value="表單3"/>
</form>
連結1和表單1:沒什麼可說的,它使用絕對路徑;
連結2和表單2:以“/”開頭,相對主機,與目前a.html的主機相同,即最終通路的頁面為http://localhost:8080/hello2/index.html;
連結3和表單3:不以“/”開頭,相對目前頁面的路徑,即a.html所有路徑,即最終通路的路徑為:http://localhost:8080/hello1/pages/index.html;
重定向1:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("/hello/index.html");
}
}
假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet
因為路徑以“/”開頭,是以相對目前主機,即http://localhost:8080/hello/index.html。
重定向2:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("index.html");
}
}
假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet
因為路徑不以“/”開頭,是以相對目前路徑,即http://localhost:8080/hello/servlet/index.html
2.1 建議使用“/”
強烈建議使用“/”開頭的路徑,這說明在頁面中的超連結和表單都要以“/”開頭,後面是目前應用的名稱,再是通路路徑:
<form action="/hello/servlet/AServlet">
</form>
<a href="/hello/b.html">連結</a>
其中/hello是目前應用名稱,這也說明如果将來修改了應用名稱,那麼頁面中的所有路徑也要修改,這一點确實是個問題。這一問題的處理方案會在學習了JSP之後講解!
在Servlet中的重定向也建議使用“/”開頭。同理,也要給出應用的名稱!例如:
response.sendRedirect("/hello/BServlet");
其中/hello是目前應用名,如果将來修改了應用名稱,那麼也要修改所有重定向的路徑,這一問題的處理方案是使用request.getContextPath()來擷取應用名稱。
response.sendRedirect(request.getContextPath() + "/BServlet");
3 伺服器端路徑
伺服器端路徑必須是相對路徑,不能是絕對路徑。但相對路徑有兩種形式:
以“/”開頭;
不以“/”開頭;
其中請求轉發、請求包含都是伺服器端路徑,伺服器端路徑與用戶端路徑的差別是:
用戶端路徑以“/”開頭:相對目前主機;
伺服器端路徑以“/”開頭:相對目前應用;
轉發1:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("/BServlet").forward(request, response);
}
}
假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet
因為路徑以“/”開頭,是以相對目前應用,即http://localhost:8080/hello/BServlet。
轉發2:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getRequestDispatcher("BServlet").forward(request, response);
}
}
假設通路AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet
因為路徑不以“/”開頭,是以相對目前應用,即http://localhost:8080/hello/servlet/BServlet。
4 <url-pattern>路徑
<url-pattern>必須使用“/”開頭,并且相對的是目前應用。
5 ServletContext擷取資源
必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭,但無論是否使用“/”開頭都是相對目前應用路徑。
例如在AServlet中擷取資源,AServlet的路徑路徑為:http://localhost:8080/hello/servlet/AServlet:
public class AServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String path1 = this.getServletContext().getRealPath("a.txt");
String path2 = this.getServletContext().getRealPath("/a.txt");
System.out.println(path1);
System.out.println(path2);
}
}
path1和path2是相同的結果:http://localhost:8080/hello/a.txt
6 Class擷取資源
Class擷取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。
package cn.itcast;
import java.io.InputStream;
public class Demo {
public void fun1() {
InputStream in = Demo.class.getResourceAsStream("/a.txt");
}
public void fun2() {
InputStream in = Demo.class.getResourceAsStream("a.txt");
}
}
其中fun1()方法擷取資源時以“/”開頭,那麼相對的是目前類路徑,即/hello/WEB-INF/classes/a.txt檔案;
其中fun2()方法擷取資源時沒有以“/”開頭,那麼相對目前Demo.class所在路徑,因為Demo類在cn.itcast包下,是以資源路徑為:/hello/WEB-INF/classes/cn/itcast/a.txt。
7 ClassLoader擷取資源
ClassLoader擷取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。但無論是否以“/”開頭,資源都是相對目前類路徑。
public class Demo {
public void fun1() {
InputStream in = Demo.class.getClassLoader().getResourceAsStream("/a.txt");
}
public void fun2() {
InputStream in = Demo.class.getClassLoader().getResourceAsStream("a.txt");
}
}
fun1()和fun2()方法的資源都是相對類路徑,即classes目錄,即/hello/WEB-INF/classes/a.txt
編碼
1 請求編碼
1.1 直接在位址欄中給出中文
請求資料是由用戶端浏覽器發送伺服器的,請求資料的編碼是由浏覽器決定的。例如在浏覽器位址欄中給出:http://localhost:8080/hello/AServlet?name=智,那麼其中“智”是什麼編碼的呢?不同浏覽器使用不同的編碼,是以這是不确定的!
IE:使用GB2312;
FireFox:使用GB2312;
Chrome:使用UTF-8;
通常沒有哪個應用要求使用者在浏覽器位址欄中輸入請求資料的,是以大家隻需了解一下即可。
1.2 在頁面中送出請求
通常向伺服器發送請求資料都需要先請求一個頁面,然後使用者在頁面中輸入資料。頁面中有超連結和表單,通過超連結和表單就可以向伺服器發送資料了。
因為頁面是伺服器發送到用戶端浏覽器的,是以這個頁面本身的編碼由伺服器決定。而使用者在頁面中輸入的資料也是由頁面本身的編碼決定的。
index.html
<!DOCTYPE html>
<html>
<head>
<title>index.html</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="/hello/servlet/AServlet">
名稱:<input type="text" name="name"/>
<input type="submit" value="送出"/>
</form>
<a href="/hello/servlet/AServlet?name=智">連結</a>
</body>
</html>
當使用者在index.html頁面中輸入資料時,都是UTF-8清單的。因為這個頁面本身就是UTF-8編碼的!
頁面的編譯就是頁面中輸入資料的編碼。
1.3 GET請求解讀編碼
當用戶端通過GET請求發送資料給伺服器時,使用request.getParameter()擷取的資料是被伺服器誤認為ISO-8859-1編碼的,也就是說用戶端發送過來的資料無論是UTF-8還是GBK,伺服器都認為是ISO-8859-1,這就說明我們需要在使用request.getParameter()擷取資料後,再轉發成正确的編碼。
例如用戶端以UTF-8發送的資料,使用如下轉碼方式:
String name = request.getParameter(“name”);
name = new String(name.getBytes(“iso-8859-1”), “utf-8”);
1.4 POST請求解讀編碼
當用戶端通過POST請求發送資料給伺服器時,可以在使用request.getParameter()擷取請求參數之前先通過request.setCharacterEncoding()來指定編碼,然後再使用reuqest.getParameter()方法來擷取請求參數,那麼就是用指定的編碼來讀取了。
也就是說,如果是POST請求,伺服器可以指定編碼!但如果沒有指定編碼,那麼預設還是使用ISO-8859-1來解讀。
request.setCharacterEncoding(“utf-8”);
String name = request.getParameter(“name”);
2 響應編碼
響應:伺服器發送給用戶端資料!響應是由response對象來完成,如果響應的資料不是字元資料,那麼就無需去考慮編碼問題。當然,如果響應的資料是字元資料,那麼就一定要考慮編碼的問題了。
response.getWriter().print(“智”);
上面代碼因為沒有設定repsonse.getWriter()字元流的編碼,是以伺服器使用預設的編碼(ISO-8859-1)來處理,因為ISO-8859-1不支援中文,是以一定會出現編碼的。
是以在使用response.getWriter()發送資料之前,一定要設定response.getWriter()的編碼,這需要使用response.setCharacterEncoding()方法:
response.setCharacterEncoding(“utf-8”);
response.getWriter().print(“智”);
上面代碼因為在使用response.getWriter()輸出之前已經設定了編碼,是以輸出的資料為utf-8編碼。但是,因為沒有告訴浏覽器使用什麼編碼來讀取響應資料,是以很可能浏覽器會出現錯誤的解讀,那麼還是會出現亂碼的。當然,通常浏覽器都支援來設定目前頁面的編碼,如果使用者在看到編碼時,去設定浏覽器的編碼,如果設定的正确那麼亂碼就會消失。但是我們不能讓使用者總去自己設定編碼,而且應該直接通知浏覽器,伺服器發送過來的資料是什麼編碼,這樣浏覽器就直接使用伺服器告訴他的編碼來解讀!這需要使用content-type響應頭。
response.setContentType(“text/html;charset=utf-8”);
response.getWriter().print(“智”);
上面代碼使用setContentType()方法設定了響應頭content-type編碼為utf-8,這不隻是在響應中添加了響應頭,還等于調用了一次response.setCharacterEncoding(“utf-8”),也就是說,通過我們隻需要調用一次response.setContentType(“text/html;charset=utf-8”)即可,而無需再去調用response.setCharacterEncoding(“utf-8”)了。
在靜态頁面中,使用<meta>來設定content-type響應頭,例如:
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
3 URL編碼
通過頁面傳輸資料給伺服器時,如果包含了一些特殊字元是無法發送的。這時就需要先把要發送的資料轉換成URL編碼格式,再發送給伺服器。
其實需要我們自己動手給資料轉換成URL編碼的隻有GET超連結,因為表單發送資料會預設使用URL編碼,也就是說,不用我們自己來編碼。
例如:“智”這兩個字通過URL編碼後得到的是:“%E4%BC%A0%E6%99%BA”。URL編碼是先需要把“智”轉換成位元組,例如我們現在使用UTF-8把“智”轉換成字元,得到的結果是:“[-28, -68, -96, -26, -103, -70]”,然後再把所有負數加上256,得到[228, 188, 160, 230, 153, 186],再把每個int值轉換成16進制,得到[E4, BC, A0, E6, 99, BA],最後再每個16進制的整數前面加上“%”。
通過URL編碼,把“智”轉換成了“%E6%99%BA”,然後發送給伺服器!伺服器會自動識别出資料是使用URL編碼過的,然後會自動把資料轉換回來。
當然,在頁面中我們不需要自己去通過上面的過程把“智”轉換成“%E6%99%BA”,而是使用Javascript來完成即可。當後面我們學習了JSP後,就不用再使用Javascript了。
<script type="text/javascript">
function _go() {
location = "/day05_2/AServlet?name=" + encodeURIComponent("智+客");
}
</script>
<a href="javascript:_go();">連結</a>
因為URL預設隻支援ISO-8859-1,這說明在URL中出現中文和一些特殊字元可能無法發送到伺服器。是以我們需要對包含中文或特殊字元的URL進行URL編碼。
伺服器會自動識别資料是否使用了URL編碼,如果使用了伺服器會自動把資料解碼,無需我們自己動手解碼。
請求響應對象
request和response
* 當伺服器接收到請求後,伺服器會建立request和response對象,把請求資料封裝到request對象中;
* 然後調用Servlet的service()方法時把這兩個對象傳遞給service()方法;
* 在service()方法中可以通過request對象擷取請求資料,可以使用response對象向用戶端完成響應;
* 每次請求伺服器都會建立新的request和response對象,即每個請求有自己獨自的request和response對象。
==============================
==============================
==============================
response對象
1. response簡介
response是響應對象,用來在Servlet的service()方法中向用戶端響應資料。
response的功能如下:
* 設定響應頭
* 發送狀态碼
* 設定響應正文
* 重定向
2. response響應正文
* ServletOutputStream getOutputStream():用來向用戶端響應位元組資料;
* PrintWriter getWriter():用來向用戶端響應字元資料;
response.getWriter().print("你好");//向用戶端響應字元資料
byte[] bytes = ...;
response.getOutputStream().write(bytes);//向用戶端響應位元組資料
3. response字元編碼
* Tomcat響應資料預設使用ISO-8859-1
* 通常浏覽器預設使用GBK編碼
* response.setCharacterEncoding("utf-8");//設定response.getWriter()的字元編碼
1)
response.getWriter().print("大家好");
因為Tomcat預設使用的是ISO-8859-1編碼,不支援中文。是以一定編碼!
2)
response.setCharacterEncoding("utf-8");
response.getWriter().print("大家好");
因為已經設定了字元流編碼為utf-8,是以響應給用戶端的資料為utf-8編碼!
但因為浏覽器預設使用的是gbk來解析響應資料,是以亂碼!如果浏覽器使用utf-8編碼,那麼就不會亂碼了。
3)
response.setCharacterEncoding("gbk");
response.getWriter().print("大家好");
因為設定了字元流編碼為gbk,是以響應給用戶端的資料為gbk編碼!
因為浏覽器預設使用gbk來解析資料,是以不會出現亂碼!如果浏覽器使用utf-8編碼,那麼就會出現亂碼!
4)
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("大家好");
setContentType()方法有兩個作用:
* 設定字元流編碼。等同與調用了response.setCharacterEncoding("utf-8");
* 設定Content-type響應頭,即通知浏覽器響應資料的編碼為utf-8。
因為設定字元流的編碼為utf-8,是以響應給用戶端資料為utf-8編碼
因為設定了Content-type頭為utf-8,是以浏覽器會使用utf-8來解析響應資料
沒有亂碼!
5)
response.setContentType("text/html;charset=gbk");
response.getWriter().print("大家好");
* 設定了字元流為gbk,是以響應給用戶端的資料為gbk
* 設定了Content-type頭為gbk,是以通知浏覽器響應資料為gbk編碼
沒有亂碼!
6)
response.setHeader("Content-type", "text/html;charset=utf-8")
等同于
repsonse.setContentType("text/html;charset=utf-8")
7)
response.getOutputStream().write("大家好".getBytes("gbk"));
響應的資料是gbk編碼
用戶端浏覽器預設使用gbk編碼
是以沒有亂碼
======================
4. response字元流緩沖區
response字元流緩沖區大小為8KB,當向字元流中寫入資料後,資料可能隻在緩沖區中,而沒有發送到浏覽器。
可以調用response.flushBuffer()或response.getWriter().flush()方法重新整理緩沖區,把資料發送到浏覽器。
======================
5. 設定響應頭
response.setHeader("Content-type", "text/html;charset=utf-8");
等同與
response.setContentType("text/html;charset=utf-8");
response.setHeader("Refresh", "5; URL=http://www.itcast.cn");
======================
6. 指定狀态碼
response.setStatus(200):設定狀态碼為200
response.sendError(404, “您要查找的資源不存在”):設定狀态碼為404
repsonse.sendError(500, “伺服器出氏了”):設定狀态碼為500
在調用sendError()方法時,不隻是設定了狀态碼,而且還會給浏覽器一個顯示錯誤的頁面。
======================
7. 重定向
response.sendStatus(302);
repsonse.setHeader("Location", "http://www.baidu.com");
快捷的方法重定向:
response.sendRedirect("http://www.baidu.com");
* 重定向是兩次請求
* 重定向不局限與目前應用,也可以是其他應用,例如重定向到百度
* 重定向響應碼為302,而且必須有Location響應頭
* 重定向與response響應流同時使用。
======================
======================
======================
request
1. request功能介紹
* 擷取請求頭
* 擷取請求參數
* Servlet三大域對象之一
* 請求包含和請求轉發
2. request域方法
* void setAttribute(String name, Object value):添加或替換request域屬性
* Object getAttribute(String name):擷取request域指定名稱的域屬性
* void removeAttribute(String name):移除request域指定名稱的域屬性
* Enumeration getAttributeNames():擷取所有request域的屬性名稱
3. request擷取請求頭
* String getHeader(String name):擷取指定名稱的請求頭
* int getIntHeader(String name):擷取指定名稱的請求頭,把值轉換成int類型。
* Enumeration getHeaderNames():擷取所有請求頭名稱
4. request請求資料相關其他方法
重點:
* String getMethod():擷取請求方式
* String getContextPath():擷取上下文路徑,即“/” + 應用名稱,例如:/day05_1
* void setCharacterEncoding(String):設定請求體的編碼
* String getRemoteAddr():擷取用戶端IP位址
非重點:
* int getContentLength():擷取請求體位元組數
* Locale getLocale():擷取請求Locale,例如zh_CN表示中文,中國
* String getCharacterEncoding():擷取請求體編碼,在沒有調用setCharacterEncoding()之前該方法傳回null
* String getQueryString():擷取參數清單,例如:username=zhangSan&password=123
* String getRequestURI():傳回請求URI路徑,從應用名稱開始,到參數之前這一段,例如:/day05_1/AServlet
* StringBuffer getRequestURL():整個請求URL,不包含參數部分
* String getServletPath():傳回Servlet路徑,從應用名稱後開始,到參數之前這一段,不包含應用名稱。
* String getServerName():傳回主機名,例如:localhost
* int getServerPort():傳回伺服器端口号,例如:8080
5. 請求參數
擷取請求參數,即擷取超連結上的參數和表單中的參數
* String getParameter(String name):擷取指定名稱的參數,如果存在同名參數,那麼該方法隻擷取第一個參數值
* String[] getParameterValues(String name):擷取指定名稱的參數,因為同名參數的存在,是以傳回值為String[]
* Enumeration getParameterNames():擷取所有參數名稱
* Map getParameterMap():擷取所有參數,封裝到Map中,key為參數名稱,value為參數值。
6. 請求包含和請求轉發
* 請求包含和請求轉發都是在一個請求中,通路兩個Servlet。
* 請求包含和請求轉發都是有一個Servlet去調用執行另一個Servlet
* 請求包含和請求轉發都可以共享request中的資料,因為都是一個請求。
* 從AServlet請求轉發到BServlet
> 在AServlet中可以設定響應頭
> 在AServlet中不能使用響應流輸出
如果在AServlet中執行了響應操作,那麼有兩種可能:
* 如果在AServlet中響應的資料導緻response送出,那麼在轉發時抛出異常;
* 如果在AServlet中響應的資料沒有導緻response送出,那麼response中的資料會被清空。
* 從AServlet請求包含BServlet
> 在AServlet可以設定響應頭
> 在AServlet可以使用響應流輸出
* 請求轉發和請求包含都要使用RequestDispatcher對象:RequestDispatcher rd = request.getRequestDispatcher("/BServlet");
* 請求轉發執行RequestDispatcher的forward()方法:rd.forward(request,response);
* 請求包含執行RequestDispatcher的include()方法:rd.include(request,response);
* 請求轉發和請求包含的路徑都是伺服器端路徑,相對目前應用
7. 請求轉發與重定向
* 請求轉發是一個請求,而重定向是兩個請求
* 請求轉發,是使用RequestDispatcher來完成,重定向使用response對象來完成
* 請求轉發的路徑都是伺服器端路徑,而重定向是用戶端路徑,需要給出應用名稱
* 請求轉發在浏覽器位址欄中的位址是第一個Servlet的路徑,而重定向在位址欄中的位址是第二個請求的Servlet的路徑
* 請求轉發中的兩個Servlet是可以共享request資料的,而重定向因為是兩個請求,是以不能共享request資料
* 請求轉發隻能轉發到本應用的其他Servlet,而重定向可以重定向到其他應用中。
8. request.getParameter()和request.getAttribute()
* getParameter()是擷取用戶端參數,它是從用戶端傳遞給伺服器的資料。
* getAttribute()是擷取伺服器端自己設定的資料,而不是用戶端的資料。
* request沒有setParameter()方法,不能自己設定參數,參數都由用戶端傳遞
* request有setAttribute()方法,在getAttribute()之前,需要先setAttribute()才能擷取到。
* getAttribute()和setAttribute()是用來在請求轉發和請求包含中的多個Servlet中共享資料。
======================
======================
======================
路徑
1. 用戶端路徑和伺服器端路徑
* 用戶端路徑需要給出應用名稱,例如:/day05_1/AServlet
* 伺服器端路徑無需給出應用名稱,例如:/AServlet
2. 用戶端路徑
1). 頁面中都是用戶端路徑:
* 超連結的href
* 表單的action
* <img>的src
2). 重定向也是用戶端路徑:response.sendRedirect("/day05_1/BServlet");
3. 伺服器端路徑
* <url-pattern>
* 請求轉發和請求包含
* ServletContext擷取資源等
======================
======================
======================
亂碼
1. 請求編碼
* 用戶端發送的資料編碼:由浏覽器來決定:
1). 如果是在位址欄中直接給出url,那麼一般都是預設為GBK,但這個可能不太大。
2). 如果是通過頁面上的表單或超連結送出請求,那麼由目前頁面的編碼來決定發送的參數的編碼。
* 無論浏覽器發送過來的是什麼編碼的資料,Tomcat都預設使用ISO-8859-1來解碼
1). POST:可以使用request.setCharacterEncoding()方法來設定請求體資料的編碼,因為POST請求參數在請求體中,是以是可以設定編碼的。在使用request.getParameter()方法擷取參數之前,先使用request.setCharacterEncoding()方法來設定編碼即可。
2). GET:沒有方法可以設定它,因為參數在url中。是以使用request.getParameter()擷取到的資料一定是錯誤的使用了iso-8859-1解碼的。可以再使用iso-8859-1把字元串轉回到byte[],再重新使用正确的編碼來解碼即可。
String s = request.getParameter("s");//使用iso-8859-1錯誤的解碼了
byte[] bytes = s.getBytes("iso-8859-1");//退回錯誤的解碼,讓字元串通過iso-8859-1傳回到位元組資料,即還原位元組資料
s = new String(bytes, "utf-8");//重新使用正确的utf-8來解碼。
内容:
* response
* request
* 編碼
* 路徑
------------------
伺服器處理請求的流程:
伺服器每次收到請求時,都會為這個請求開辟一個新的線程。
伺服器會把用戶端的請求資料封裝到request對象中,request就是請求資料的載體!(袋子)
伺服器還會建立response對象,這個對象與用戶端連接配接在一起,它可以用來向用戶端發送響應。(手機)
------------------
response:其類型為HttpServletResponse
ServletResponse-->與協定無關的類型
HttpServletResponse-->與http協定相關的類型
回憶一下http協定!http協定中響應的内容包含哪些東西呢?
* 狀态碼:200表示成功、302表示重定向、404表示用戶端錯(通路的資源不存在)、500表示伺服器端錯
> sendError(int sc) --> 發送錯誤狀态碼,例如404、500
> sendError(int sc, String msg) --> 也是發送錯誤狀态碼,還可以帶一個錯誤資訊!
> setStatus(int sc) --> 發送成功的狀态碼,可以用來發送302
案例:
> 發送404
* 響應頭:Content-Type、Refresh、Location等等
頭就是一個鍵值對!可能會存在一個頭(一個名稱,一個值),也可能會存在一個頭(一個名稱,多個值!)
> *****setHeader(String name, String value):适用于單值的響應頭,例如:response.setHeader("aaa", "AAA");
> addHeader(String name, String value):适用于多值的響應頭
response.addHeader("aaa", "A");
response.addHeader("aaa", "AA");
response.addHeader("aaa", "AAA");
> setIntHeader(String name, int value):适用于單值的int類型的響應頭
` response.setIntHeader("Content-Length", 888);
> addIntHeader(String name, int value):适用于多值的int類型的響應頭
> setDateHeader(String name, long value):适用于單值的毫秒類型的響應頭
response.setDateHeader("expires", 1000 * 60 * 60 * 24);
> addDateHeader(String name, long value):适用于多值的毫秒類型的響應頭
案例:
> 發送302,設定Location頭,完成重定向!
> 定時重新整理:設定Refresh頭,你可以把它了解成,定時重定向!
> 禁用浏覽器緩存:Cache-Control、pragma、expires
> <meta>标簽可以代替響應頭:<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
* 響應體:通常是html、也可以是圖檔!
> response的兩個流:
<> ServletOutputStream,用來向用戶端發送位元組資料。ServletOutputStream out = resopnse.getOutputStream();
<> PrintWriter,用來向用戶端發送字元資料!需要設定編碼。PrintWriter writer = response.getWriter();
<> 兩個流不能同時使用!
案例:
> 使用PrintWriter發送字元資料
> 使用ServletOutputStream發送位元組資料(圖檔)
* 重定向:設定302,設定Location!其中變化的隻有Location,是以java提供了一個快捷方法,完成重定向!
> sendRedirect(String location)方法
------------------
request --> 封裝了用戶端所有的請求資料!
請求行
請求頭
空行
請求體(GET沒體)
回憶一下http協定!請求協定中的資料都可以通過request對象來擷取!
* 擷取常用資訊
> 擷取用戶端IP,案例:封IP。request.getRemoteAddr()
> 請求方式,request.getMethod(),可能是POST也可能是GET
* 擷取HTTP請求頭
> *****String getHeader(String name),适用于單值頭
> int getIntHeader(String name),适用于單值int類型的請求頭
> long getDateHeader(String name),适用于單值毫秒類型的請求頭
> Enumeration<String> getHeaders(String name),适用于多值請求頭
案例:
> 通過User-Agent識别使用者浏覽器類型
> 防盜鍊:如果請求不是通過本站的超連結發出的,發送錯誤狀态碼404。Referer這個請求頭,表示請求的來源!
* 擷取請求URL
http://localhost:8080/day10_2/AServlet?username=xxx&password=yyy
> String getScheme():擷取協定,http
> String getServerName():擷取伺服器名,localhost
> String getServerPort():擷取伺服器端口,8080
> *****String getContextPath():擷取項目名,/day10_2
> String getServletPath():擷取Servlet路徑,/AServlet
> String getQueryString():擷取參數部分,即問号後面的部分。username=xxx&password=yyy
> String getRequestURI():擷取請求URI,等于項目名+Servlet路徑。/day10_2/AServlet
> String getRequestURL():擷取請求URL,等于不包含參數的整個請求路徑。http://localhost:8080/day10_2/AServlet
* 擷取請求參數:請求參數是由用戶端發送給伺服器的!有可能是在請求體中(POST),也可能是在URL之後(GET)
請求參數:有一個參數一個值的,還有一個參數多個值!
> *****String getParameter(String name):擷取指定名稱的請求參數值,适用于單值請求參數
> String[] getParameterValues(String name):擷取指定名稱的請求參數值,适用于多值請求參數
> Enumeration<String> getParameterNames():擷取所有請求參數名稱
> *****Map<String,String[]> getParameterMap():擷取所有請求參數,其中key為參數名,value為參數值。
案例:超連結參數
案例:表單資料
* 請求轉發和請求包含
RequestDispatcher rd = request.getRequestDispatcher("/MyServlet"); 使用request擷取RequestDispatcher對象,方法的參數是被轉發或包含的Servlet的Servlet路徑
請求轉發:*****rd.forward(request,response);
請求包含:rd.include(request,response);
有時一個請求需要多個Servlet協作才能完成,是以需要在一個Servlet跳到另一個Servlet!
> 一個請求跨多個Servlet,需要使用轉發和包含。
> 請求轉發:由下一個Servlet完成響應體!目前Servlet可以設定響應頭!(留頭不留體)
> 請求包含:由兩個Servlet共同未完成響應體!(都留)
> 無論是請求轉發還是請求包含,都在一個請求範圍内!使用同一個request和response!
* request域
Servlet中三大域對象:request、session、application,都有如下三個方法:
> void setAttribute(String name, Object value)
> Object getAttribute(String name)
> void removeAttribute(String name);
> 同一請求範圍内使用request.setAttribute()、request.getAttribute()來傳值!前一個Servlet調用setAttribute()儲存值,後一個Servlet調用getAttribute()擷取值。
* 請求轉發和重定向的差別
> 請求轉發是一個請求一次響應,而重定向是兩次請求兩次響應
> 請求轉發位址欄不變化,而重定向會顯示後一個請求的位址
> 請求轉發隻能轉發到本項目其他Servlet,而重定向不隻能重定向到本項目的其他Servlet,還能定向到其他項目
> 請求轉發是伺服器端行為,隻需給出轉發的Servlet路徑,而重定向需要給出requestURI,即包含項目名!
> 請求轉發和重定向效率是轉發高!因為是一個請求!
<> 需要位址欄發生變化,那麼必須使用重定向!
<> 需要在下一個Servlet中擷取request域中的資料,必須要使用轉發!
------------------
編碼
常見字元編碼:iso-8859-1(不支援中文)、gb2312、gbk、gb18030(系統預設編碼,中國的國标碼)、utf-8(萬國碼,支援全世界的編碼,是以我們使用這個)
1. 響應編碼
* 當使用response.getWriter()來向用戶端發送字元資料時,如果在之前沒有設定編碼,那麼預設使用iso,因為iso不支援中文,一定亂碼
* 在使用response.getWriter()之前可以使用response.setCharaceterEncoding()來設定字元流的編碼為gbk或utf-8,當然我們通常會選擇utf-8。這樣使用response.getWriter()發送的字元就是使用utf-8編碼的。但還是會出現亂碼!因為浏覽器并不知道伺服器發送過來的是什麼編碼的資料!這時浏覽器會使用gbk來解碼,是以亂碼!
* 在使用response.getWriter()之前可以使用response.setHeader("Content-type","text/html;charset=utf-8")來設定響應頭,通知浏覽器伺服器這邊使用的是utf-8編碼,而且在調用setHeader()後,還會自動執行setCharacterEncding()方法。這樣浏覽器會使用utf-8解碼,是以就不會亂碼了!
* setHeader("Content-Type", "text/html;charset=utf-8")的快捷方法是:setContentType("text/html;charset=utf-8)。
2. 請求編碼
* 用戶端發送給伺服器的請求參數是什麼編碼:
用戶端首先要打開一個頁面,然後在頁面中送出表單或點選超連結!在請求這個頁面時,伺服器響應的編碼是什麼,那麼用戶端發送請求時的編碼就是什麼。
* 伺服器端預設使用什麼編碼來解碼參數:
伺服器端預設使用ISO-8859-1來解碼!是以這一定會出現亂碼的!因為iso不支援中文!
* 請求編碼處理分為兩種:GET和POST:GET請求參數不在請求體中,而POST請求參數在請求體中,是以它們的處理方式是不同的!
* GET請求編碼處理:
> String username = new String(request.getParameter("iso-8859-1"), "utf-8");
> 在server.xml中配置URIEncoding=utf-8
* POST請求編碼處理:
> String username = new String(request.getParameter("iso-8859-1"), "utf-8");
> 在擷取參數之前調用request.setCharacterEncoding("utf-8");
3. URL編碼
表單的類型:Content-Type: application/x-www-form-urlencoded,就是把中文轉換成%後面跟随兩位的16進制。
為什麼要用它:在用戶端和伺服器之間傳遞中文時需要把它轉換成網絡适合的方式。
* 它不是字元編碼!
* 它是用來在用戶端與伺服器之間傳遞參數用的一種方式!
* URL編碼需要先指定一種字元編碼,把字元串解碼後,得到byte[],然後把小于0的位元組+256,再轉換成16進制。前面再添加一個%。
* POST請求預設就使用URL編碼!tomcat會自動使用URL解碼!
* URL編碼:String username = URLEncoder.encode(username, "utf-8");
* URL解碼:String username = URLDecoder.decode(username, "utf-8");
最後我們需要把連結中的中文參數,使用url來編碼!今天不行,因為html中不能給出java代碼,但後面學了jsp就可以了。
------------------
路徑
* web.xml中<url-pattern>路徑,(叫它Servlet路徑!)
> 要麼以“*”開關,要麼為“/”開頭
* 轉發和包含路徑
> *****以“/”開頭:相對目前項目路徑,例如:http://localhost:8080/項目名/ request.getRequestdispacher("/BServlet").for...();
> 不以“/”開頭:相對目前Servlet路徑。 request.getRequestdispacher("/BServlet").for...();,假如目前Servlet是:http://localhost:8080/項目名/servlet/AServlet, 就是http://localhost:8080/項目名/servlet/BServlet
* 重定向路徑(用戶端路徑)
> 以“/”開頭:相對目前主機,例如:http://localhost:8080/, 是以需要自己手動添加項目名,例如;response.sendRedirect("/day10_1/Bservlet");
* 頁面中超連結和表單路徑
> 與重定向相同,都是用戶端路徑!需要添加項目名
> <form action="/day10_1/AServlet">
> <a href="/day10_/AServlet">
> <a href="AServlet">,如果不以“/”開頭,那麼相對目前頁面所在路徑。如果是http://localhost:8080/day10_1/html/form.html。 即:http://localhost:8080/day10_1/html/ASevlet
> *****建立使用以“/”開頭的路徑,即絕對路徑!
* ServletContext擷取資源路徑
> 相對目前項目目錄,即當然index.jsp所在目錄
* ClassLoader擷取資源路徑
> 相對classes目錄
* Class擷取資源路徑
> 以“/”開頭相對classes目錄
> 不以“/”開頭相對目前.class檔案所在目錄。
GET請求編碼:
URL編碼:
請求編碼:
請求參數和request域:
請求轉發和請求包含是一個請求:
響應編碼:
重定向: