JavaWeb

目錄
? ? 1 Socket
? ? 2 軟件結(jié)構(gòu)
? ? 3 Servlet
? ? 4 HTTP
????5 單點(diǎn)登錄SSO
? ? 6 常見問題總結(jié)

參考資料
? ? · 《深入分析 Java Web》

1 Socket

1.1 概念

? ? 套接字(socket)肛真,是描述計(jì)算機(jī)之間完成相互網(wǎng)絡(luò)通信的抽象功能,沒有對應(yīng)的實(shí)體蝶糯。通訊的兩端都有Sokcet,數(shù)據(jù)在兩個Sokcet間通過IO傳輸渣叛。

? ? 格式為:IP:端口號

1.2 分類

? ? · TCP和UDP

? ? ·?兩種方式傳輸數(shù)據(jù)都是通過序列化java對象后粘秆,通過二進(jìn)制協(xié)議傳輸粹胯,故Socket通信和編程語言沒有關(guān)系。

2 軟件結(jié)構(gòu)

2.1 C/S體系

? ? Client-Server 客戶端-服務(wù)器端咨演。屬于桌面應(yīng)用程序闸昨。
? ? · 弊端:
? ? ? ? ·需要安裝軟件
? ? ? ? ·維護(hù)難,占空間
? ? ? ? ·服務(wù)端升級,客戶端也需要升級
? ? · 優(yōu)點(diǎn):
? ? ? ? ·體驗(yàn)效果好
? ? ? ? ·占寬帶小
? ? ? ? ·減輕服務(wù)器端壓力

2.2 B/S體系

? ? Browser-Server瀏覽器端-服務(wù)器端饵较,屬于網(wǎng)站應(yīng)用程序拍嵌。
? ? · 弊端:
? ? ? ? ·需要使用瀏覽器訪問
? ? ? ? ·兼容性差、安全性差
? ? ? ? ·服務(wù)器端壓力大
? ? · 優(yōu)點(diǎn):
? ? ? ? ·不需要特定客戶端
? ? ? ? ·服務(wù)端升級循诉,瀏覽器不需要升級横辆。

3 Servlet

3.1 資源的分類

? ? · 靜態(tài)資源:當(dāng)用戶多次訪問這個資源,資源的源代碼永遠(yuǎn)不會改變的資源茄猫。

? ? · 動態(tài)資源:當(dāng)用戶多次訪問這個資源狈蚤,資源的源代碼可能會發(fā)送改變。

3.2 實(shí)質(zhì)

? ? Servlet本質(zhì)是Server Applet 服務(wù)連接器划纽。是服務(wù)器端的程序脆侮,具有獨(dú)立平臺和協(xié)議的特性,用于交互式地瀏覽和生成數(shù)據(jù)勇劣,生成動態(tài)Web內(nèi)容靖避。

3.3 使用

? ? 編寫類繼承HttpServlet類,并覆蓋doGet和doPost方法比默,并在web.xml文件或者使用@WebServlet注解配置訪問路徑幻捏。

public?class?HelloServlet?extends?HttpServlet{

????@Override

? ??protected?void?doGet(HttpServletRequest req, HttpServletResponse resp)?throws?ServletException, IOException {

????????//解決中文亂碼問題

???????resp.setCharacterEncoding("utf-8");//內(nèi)容編碼,防止出現(xiàn)中文亂碼

????????resp.setContentType("text/html;charset=utf-8"); //向?yàn)g覽器輸出內(nèi)容

????????resp.getWriter().write("這是第一個servlet程序。當(dāng)前時間為:"+new?Date());

????}

}

3.4 工作原理

3.4.1 Servlet容器

? ? servlet容器的產(chǎn)生是為了技術(shù)上的解耦,通過標(biāo)準(zhǔn)化接口來相互協(xié)作。? ??

圖3-1 Tomcat容器

? ? 圖中看出,真正管理servlet的容器是Context容器鳍寂,且一個Context對應(yīng)一個Web工程。

3.4.2 Servlet容器的啟動

Tomcat啟動代碼

Tomcat tomcat=getTomcatInstance();
File appDir= new File(getBuildDirectory(), "webapps/examples") ;
tomcat. addWebapp(null, "/examplesappDir. getAbsolutePath());
tomcat. start();
ByteChunk res = geturl( "http://localhost:"+getport()+" /examples/servlets/servlet/HelloWorldExample");
assertTrue(res tostring().indexOf(<h1>Hello World! </h1>")>0);

public Context addwebapp (Hosthost, String url, String path){
????silence(url);
????Context ctx? = new StandardContext();
? ? ?ctx.setPath( url);
?????ctx. setDocBase(path);
?????if(defaultRealm== null){
?????????initsimpleAuth();
? ? }
?????ctx. setRealm(defaultRealm);
? ? ?ctx. addLifecycleListener(new DefaultWebXmlListener());
?????Contextconfig ctxCfg = new ContextConfig();
?????ctx. addLifecycleListener(ctxCfg);
? ? ?ctxcfg. setDefaultwebXml ("org/apache/catalin/startup/DEFAULT_XMI ") ;
? ? ?if(host == null){
? ? ? ? ?getHost(). addchild (ctx)勺鸦;
? ? ?} else{
?????????host.addchild(ctx);
? ? ?}
? ? ?return ctx妨退;

(1)Tomcat啟動過程

? ? ????·getTomcatInstance()獲取Tomcat實(shí)例
? ? ? ? ·新建StandardContext()容器,并設(shè)置訪問URl和項(xiàng)目文件訪問地址
? ? ? ? ·添加LifecycleListener
? ? ? ? ·新建ContextConfig锭魔。解析Web應(yīng)用的配置文件web.xml等
? ? ? ? ·tomcat實(shí)例執(zhí)行addWebapp()
? ? ? ? ·tomcat實(shí)例執(zhí)行start()例证,啟動整個Tomcat容器。

(2)tomcat所有的容器都集成Lifecycle接口迷捧,Lifecycle接口管理著容器的整個生命周期织咧,所有容器的修改和狀態(tài)的改變都會由它去通知已經(jīng)注冊的觀察者(Listener)。這是基于觀察者模式設(shè)計(jì)的漠秋。

(3)Context容器的啟動

? ? ? ? 在tomcat容器啟動后笙蒙,當(dāng)Context容器處于init初始化狀態(tài)時,其中的Listener將會被調(diào)用庆锦。

????????首先執(zhí)行ContextConfig的Init方法:
? ? ? ? ? ? · 創(chuàng)建用于解析XML配置文件的contextDigester對象
? ? ? ? ? ? ·?讀取默認(rèn)的 context. xm配置文件,如果存在則解析它捅位。
? ? ? ? ? ? · 讀取默認(rèn)的Hos配置文件,如果存在則解析它
? ? ? ? ? ? · 讀取默認(rèn)的 Context自身的配置文件,如果存在則解析它
? ? ? ? ? ? · 設(shè)置 Context的 DocBase

????????ContextConfig的init方法完成后, Context容器就會執(zhí)行startInternal()方法,這個方法的啟動邏輯比較復(fù)雜,主要包括如下幾部分:
? ? ? ? ? ? · 創(chuàng)建讀取資源文件的對象
? ? ? ? ? ? · 創(chuàng)建 ClassLoader對象
? ? ? ? ? ? · 設(shè)置應(yīng)用的工作目錄
? ? ? ? ? ? · 啟動相關(guān)的輔助類,如 logger、 realm、 resources等艇搀。
? ? ? ? ? ? · 修改啟動狀態(tài),通知感興趣的觀察者(Web應(yīng)用的配置)
? ? ? ? ? ? · 子容器的初始化
? ? ? ? ? ? · 獲取 ServletContext并設(shè)置必要的參數(shù)尿扯。
? ? ? ? ? ? · 初始化“ load on startup”的 Servlet. 其他Servlet在第一次被調(diào)用的時候初始化。

? ? ? ? 在初始化時焰雕,會將Servlet包裝成StandardWrapper衷笋。因?yàn)镾tandardWrapper是Tomcat容器中的一部分,它具有容器的特性矩屁,而Servlet作為一個獨(dú)立的Web開發(fā)標(biāo)準(zhǔn)辟宗,不應(yīng)該強(qiáng)耦合在Tomcat中。

3.4.3 Servlet實(shí)例的建立和初始化

(1)創(chuàng)建實(shí)例

? ? ? ? web.xml中的配置項(xiàng)吝秕,“l(fā)oad-on-startup”如果大于0慢蜓,則在Tomcat啟動時Servlet就會被啟動。調(diào)用Wrapper.loadServlet方法獲取servletClass郭膛,并交給InstanceManager去創(chuàng)建對象晨抡。

(2)初始化實(shí)例

? ? ? ? 調(diào)用StandardWrapper的InitServlet方法初始化對象。

3.4.4 Servlet體系結(jié)構(gòu)

? ? · ServletConfig则剃,在Servlet初始化時就傳到Servlet耘柱,以StandardWrapperFacade對象的形式調(diào)用,可以防止暴露不必要的數(shù)據(jù)棍现。

? ? · ServletContext调煎,獲取Context容器的信息。

? ? · ServletRquest

? ? · ServletResponse

? ? 體系設(shè)計(jì)過程中用到門面設(shè)計(jì)模式己肮。

3.4.5 Servlet調(diào)用

(1)訪問URL:http://hostname:port/contextpath/servletPath

(2)Tomcat中的org.apache.tomcat.util.http.mapper完成URL到一個Servlet子容器的映射工作士袄。Mapper類保存了Tomcat的Container容器中的所有子容器的信息,根據(jù)傳入Servlet容器的請求的hostname和contextpath設(shè)置到request的mappingData屬性中谎僻。

(3)Mapper子類MapperListener作為監(jiān)聽這監(jiān)聽容器的變化娄柳,這樣其中的mapper屬性也相應(yīng)修改。

(4)執(zhí)行Servlet接口service(ServletRequest req, ServletResponse resp)方法艘绍。

3.4.6 Filter

3.4.6.1 簡介

????Filter也稱之為過濾器赤拒,它是 Servlet 技術(shù)中最實(shí)用的技術(shù),Web 開發(fā)人員通過 Filter 技術(shù)诱鞠,對 web 服務(wù)器管理的所有 web 資源:例如 Jsp, Servlet, 靜態(tài)圖片文件或靜態(tài) html 文件等進(jìn)行攔截挎挖,從而實(shí)現(xiàn)一些特殊的功能。例如實(shí)現(xiàn) URL 級別的權(quán)限訪問控制航夺、過濾敏感詞匯蕉朵、壓縮響應(yīng)信息等一些高級功能。

????它主要用于對用戶請求進(jìn)行預(yù)處理阳掐,也可以對HttpServletResponse進(jìn)行后處理始衅。使用 Filter 的完整流程:Filter 對用戶請求進(jìn)行預(yù)處理堪伍,接著將請求交給 Servlet 進(jìn)行處理并生成響應(yīng),最后 Filter 再對服務(wù)器響應(yīng)進(jìn)行后處理觅闽。

3.4.6.2 Demo

/**

*? 使用Filter 打印參數(shù)

* @author Administrator

*

*/

public class FilterDemo implements Filter {

? ? public? FilterDemo(){

? ? ???? System.out.println("FilterDemo 構(gòu)造函數(shù)被執(zhí)行...");

? ? }

/**

* 銷毀

*/

????public void destroy() {

? ? ????System.out.println("destroy");

????}

/*
????用戶在每個請求進(jìn)來時帝雇,訪問doFilter方法,在Servlet的service方法之前調(diào)用蛉拙。

*/

????public void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse,

????????????????FilterChain paramFilterChain) throws IOException, ServletException {

? ? ????System.out.println("doFilter");

????????HttpServletRequest request = (HttpServletRequest) paramServletRequest;

????????HttpServletResponse response = (HttpServletResponse) paramServletResponse;

????????// 請求地址

????????String requestURI = request.getRequestURI();

????????System.out.println("requestURI:"+requestURI);

????????// 參數(shù)

????????Map<String, String[]> parameterMap = request.getParameterMap();

????????for (String key : parameterMap.keySet()) {

????????String[] arr=parameterMap.get(key);

????????}

????}

/**

* 初始化

*/

????public void init(FilterConfig paramFilterConfig) throws ServletException {

????????System.out.println("init");

????}

}

<filter>

? <filter-name>FilterDemo</filter-name>

? <filter-class>com.qian.servlet.FilterDemo</filter-class>

</filter>

<filter-mapping>

????<filter-name>FilterDemo</filter-name>

????<url-pattern>/*</url-pattern>

</filter-mapping>

3.4.6.3 相關(guān)類

(1)FilterConfig

? ? ? ? 可以通過其獲取ServletContext對象尸闸。

(2)FilterChain

? ? ? ? 責(zé)任鏈設(shè)計(jì)模式。FilterChain是doFilter方法的傳入?yún)?shù)孕锄,保存了當(dāng)前整個請求鏈吮廉。通過調(diào)用FilterChain.doFilter方法,可以將請求繼續(xù)傳遞下去畸肆,但是如果要攔截請求宦芦,則不調(diào)用。

? ? ? ? 當(dāng)FilterChain上所有的Filter對象執(zhí)行完成后轴脐,才會執(zhí)行最終的Servlet调卑。

3.4.6.4 注意事項(xiàng)

(1)Filter常用于登錄、XSS攻擊大咱、權(quán)限方面恬涧。

(2)Filter是單例的,與Servlet類似碴巾。

3.5 Servlet生命周期

3.5.1 Servlet接口方法

public class TestServletService implements Servlet{

????@Override

????public void destroy() {

????????// TODO 自動生成的方法存根

????}

????@Override

????public ServletConfig getServletConfig() {

????????// TODO 自動生成的方法存根

????????return null;

????}

????@Override

????public String getServletInfo() {

????????// TODO 自動生成的方法存根

????????return null;

????}

????@Override

????public void init(ServletConfig arg0) throws ServletException {

????????// TODO 自動生成的方法存根

????}

????@Override

????public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {

????????// TODO 自動生成的方法存根

????}

}

其中溯捆,與生命周期相關(guān)的有四個方法:

(1)構(gòu)造方法:創(chuàng)建servlet對象的時候調(diào)用。默認(rèn)情況下厦瓢,第一次訪問(擁有l(wèi)oad-on-startup設(shè)置的除外)servlet的時候創(chuàng)建servlet對象只調(diào)用1次提揍。證明servlet對象在tomcat是單實(shí)例的

(2)init方法: 創(chuàng)建完servlet對象的時候調(diào)用煮仇。只調(diào)用1次劳跃。

(3)service方法: 每次發(fā)出請求時調(diào)用。調(diào)用n次欺抗。

(4)destroy方法: 銷毀servlet對象的時候調(diào)用售碳。停止服務(wù)器或者重新部署web應(yīng)用時銷毀servlet對象。只調(diào)用1次绞呈。

3.5.2 Tomcat內(nèi)部代碼運(yùn)行

(1)通過配置文件的映射關(guān)系,找到ServletClass內(nèi)容间景。

(2)通過反射構(gòu)造Servlet對象

(3)創(chuàng)建ServletConfig對象佃声,反射調(diào)用init方法。

(4)創(chuàng)建request倘要、response對象圾亏,反射調(diào)用service方法十拣。

(5)銷毀servlet時,反射調(diào)用destroy方法志鹃。

3.5.3 時序圖

圖3-2 Servlet生命周期時序圖

3.6 Servlet多線程問題

(1)servlet對象在tomcat服務(wù)器是單實(shí)例多線程的夭问,為每個用戶請求分配一個線程,可以通過線程池來管理曹铃。

(2)因?yàn)閟ervlet是多線程的缰趋,所以當(dāng)多個servlet的線程同時訪問了servlet的共享數(shù)據(jù),如成員變量陕见,可能會引發(fā)線程安全問題秘血。

????????解決辦法:

?????????????· 把使用到共享數(shù)據(jù)的代碼塊進(jìn)行同步(使用synchronized關(guān)鍵字進(jìn)行同步)

? ? ? ? ? ? ?· 建議在servlet類中盡量不要使用成員變量。如果確實(shí)要使用成員评甜,必須同步灰粮。而且盡量縮小同步代碼塊的范圍。(哪里使用到了成員變量忍坷,就同步哪里U持邸!)佩研,以避免因?yàn)橥蕉鴮?dǎo)致并發(fā)效率降低蓖乘。

3.7 域?qū)ο?/h2>

(1)作用: 用于保存數(shù)據(jù)、獲取數(shù)據(jù)韧骗,可以在不同的動態(tài)資源之間共享數(shù)據(jù)嘉抒。

(2)使用:

????????· 保存數(shù)據(jù) setAttribute(String,Object)

????????· 獲取數(shù)據(jù) Object getAttribute(String)

????????· 刪除數(shù)據(jù) removeAttribute(String)

(3)分類:

? ? ? ? · HttpServletRequest

? ? ? ? · HttpSession 會話對象

? ? ? ? · PageContext

? ? ? ? · ServletContext 作用范圍為整個Web應(yīng)用

(4)可以通過getContextPath()方法獲取上下文路徑

3.8 轉(zhuǎn)發(fā)與重定向

(1)轉(zhuǎn)發(fā):

? ? ? ? · 地址欄不會改變

? ? ? ? · 只能轉(zhuǎn)發(fā)到當(dāng)前web應(yīng)用

? ? ? ? · 可以把數(shù)據(jù)保存到request域

? ? ? ? · request.getRequestDispatcher(String).forward(request袍暴,response)

(2)重定向:

? ? ? ? · 地址欄改變

? ? ? ? · 可以跳轉(zhuǎn)到其他web應(yīng)用

? ? ? ? · 不能使用request數(shù)據(jù)(涉及到2次瀏覽器請求)

? ? ? ? · response.sendRedirect(String)

3.9 Cookie

? ? 會話數(shù)據(jù)保存在客戶端些侍。瀏覽器在每次訪問服務(wù)端時,都會帶著cookie信息政模。

關(guān)于Cookie的跨域問題:cookie 跨域問題_chou_out_man的博客-CSDN博客_cookie跨域

3.9.1 使用

(1)構(gòu)造Cookie對象

????????Cookie(java.lang.String name, java.lang.String value)

(2)設(shè)置cookie

????????void setPath(java.lang.String uri) ?:設(shè)置cookie的有效訪問路徑

????????void setMaxAge(int expiry):設(shè)置cookie的有效時間
? ? ? ? ? ? ? ? · 不設(shè)置岗宣,則隨瀏覽器關(guān)閉而消失
? ? ? ? ? ? ? ? · 整數(shù)(正負(fù)均可),cookie保存到瀏覽器淋样,緩存在硬盤中
? ? ? ? ? ? ? ? · 零耗式,不保存cookie

????????void setValue(java.lang.String newValue) :設(shè)置cookie的值

(3)發(fā)送cookie到瀏覽器端保存

????????void response.addCookie(Cookie cookie) ?:發(fā)送cookie

(4)服務(wù)器接收cookie

????????Cookie[] request.getCookies() :接收cookie

3.9.2 Demo

@WebServlet("/LastAccessTime")

public class LastAccessTime extends HttpServlet {

????@Override

????protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

????????resp.setContentType("text/html;charset=utf-8");// 防止瀏覽器顯示亂碼

????????String lastAccessTime = null;

????????Cookie[] cookies = req.getCookies();

????????for (Cookie cookie : cookies) {

????????????String name = cookie.getName();

????????????if (name.equals("lastAccessTime")) {

????????????????astAccessTime = cookie.getValue();

????????????????break;

????????????}

????????}

????????if (StringUtils.isEmpty(lastAccessTime)) {

????????????????resp.getWriter().print("您是首次訪問!");

????????} else {

????????????????resp.getWriter().print("你上次訪問時間:" + lastAccessTime);

????????}

????// 保存訪問時間

????// 創(chuàng)建cookie 將當(dāng)前時間作為cookie保存到瀏覽器

????String currenttime = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss").format(new Date());

????Cookie cookie = new Cookie("lastAccessTime", currenttime);

????cookie.setMaxAge(60 * 60 * 24);

????// 發(fā)送cookie

????resp.addCookie(cookie);

????}

}

3.9.3 工作原理

? ? 真正構(gòu)建Cookie是在org.apache.catalina.connector.Response類中,調(diào)用generateCookieString方法將Cookie對象構(gòu)造成一個String字符串趁猴,并將字符串命名為Set-Cookie添加到Header中刊咳。

3.9.4 利弊分析

????弊端

? ? ? ? · 只能存字符串類型,不能保存對象

? ? ? ? · 只能存非中文

? ? ? ? · 1個Cookie的容量不超過4KB儡司,最多300個

? ? ? ? · 安全性差

3.9.5 壓縮cookie

(1)采用文本壓縮方式娱挨。可采用gzip或者deflate算法

(2)壓縮后進(jìn)行轉(zhuǎn)碼捕犬,采用Base32或者Base64跷坝。因?yàn)镃ookie中不能包含控制字符酵镜,只能包含ASCII碼中34~126的可見字符。

3.10 Session

? ? 會話數(shù)據(jù)保存在服務(wù)器端(內(nèi)存中)柴钻。

3.10.1 使用

HttpSession類:用于保存會話數(shù)據(jù)

(1)創(chuàng)建或得到session對象

????????HttpSession getSession()?

????????HttpSession getSession(boolean create)?

(2)設(shè)置session對象

????????void setMaxInactiveInterval(int interval)? : 設(shè)置session的有效時間

????????void invalidate()? ? : 銷毀session對象

????????java.lang.String getId()? : 得到session編號

(3)保存會話數(shù)據(jù)到session對象

????????void setAttribute(java.lang.String name, java.lang.Object value)? : 保存數(shù)據(jù)

????????java.lang.Object getAttribute(java.lang.String name)? : 獲取數(shù)據(jù)

????????void removeAttribute(java.lang.String name) : 清除數(shù)據(jù)

3.10.2 demo

@WebServlet("/TestSession")

public class TestSession extends HttpServlet {

????private static final long serialVersionUID = 1L;

? ? /**

? ? * @see HttpServlet#HttpServlet()

? ? */

? ? public TestSession() {

? ? ? ? super();

? ? ? ? // TODO Auto-generated constructor stub

? ? }

/**

* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)

*/

????protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

????????// TODO Auto-generated method stub

????????response.setContentType("text/html;charset=utf-8");// 防止瀏覽器顯示亂碼

????????HttpSession session = request.getSession();

????????String lastTime = (String) session.getAttribute("lastTime");

????????if(lastTime == null) {

????????????response.getWriter().write("這是第一次訪問");

????????}else {

????????????response.getWriter().write("上次訪問時間:" + lastTime + "現(xiàn)在: " + new Date());

????????}

????????session.setMaxInactiveInterval(60 * 60 * 24);

????????session.setAttribute("lastTime", new Date()+ "");

????}

}

3.10.3 與Cookie關(guān)系

(1)服務(wù)器生成唯一對應(yīng)session對象的JSESSIONID淮韭,并作為cookie發(fā)送到瀏覽器端保存。

(2)如果瀏覽器禁用cookie可以將JSESSIONID寫到用戶請求的URL中贴届。

(3)如何避免瀏覽器的JSESSIONID的cookie隨著瀏覽器關(guān)閉而丟失的問題

/**

* 手動發(fā)送一個硬盤保存的cookie給瀏覽器

*/

Cookie c = new Cookie("JSESSIONID",session.getId());

c.setMaxAge(60*60);

response.addCookie(c);

3.10.4 工作原理

(1)request.getSession()方法靠粪,觸發(fā)創(chuàng)建session對象,并加入到org.apache.catalina.Manager的session容器中保存粱腻。

(2)Manager負(fù)責(zé)servlet容器中所有session的生命周期管理庇配。當(dāng)servlet容器重啟或者關(guān)閉時,Manager負(fù)責(zé)持久化(調(diào)用upload方法)沒有過期的session對象到“SESSIONS.ser”文件中绍些,也會定期檢測過期捞慌。

3.10.5 分布式session

圖3-3 分布式session

(1)服務(wù)訂閱服務(wù)器,集中管理資源和配置柬批,統(tǒng)一通過它來推送配置啸澡。可以使用Zookeeper實(shí)現(xiàn)氮帐。

(2)分布式緩存嗅虏,存儲共享集群中每臺集群的session。

(3)存取方式上沐。
? ? ? ? · 自定義InnerHttpSession類重新實(shí)現(xiàn)HttpSession接口皮服。
? ? ? ? · 通過Filter攔截用戶請求,將自己設(shè)置的InnerHttpSession對象設(shè)置到request和response對象中参咙。
? ? ? ? · 應(yīng)用創(chuàng)建的所有Session對象都保存在InnerHttpSession對象中龄广,訪問完成后將InnerHttpSession內(nèi)容更新到分布式緩存中。

3.10.6 跨域名共享Cookie

(1)利用跳轉(zhuǎn)應(yīng)用支持多個域名的訪問蕴侧,并將同一個sessionID作為cookie寫到多個域名下择同。

(2)多個域名,根據(jù)sessionID在分布緩存中拿取session信息净宵。

3.10.7 表單重復(fù)提交問題

(1)原因

? ? ? ? · 網(wǎng)絡(luò)延時

? ? ? ? · 瀏覽器重新刷新按鈕

? ? ? ? · 瀏覽器“回退”按鈕敲才,再提交。

(2)解決方案

? ? ? ? · 利用javaScript代碼進(jìn)行標(biāo)識

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Form表單</title>

<script type="text/javascript">

????var isFlag = false; //表單是否已經(jīng)提交標(biāo)識择葡,默認(rèn)為false

????function submitFlag() {

????if (isFlag == false) {

????????isFlag = true;

????????return true;

????} else {

????????return false;

????}

}

</script>

</head>

<body>

<form action="${pageContext.request.contextPath}/DoFormServlet"? ?method="post" onsubmit="return submitFlag()">

????用戶名:<input type="text" name="userName"> <input type="submit"? ?value="提交" id="submit">

</form>

</body>

</html>

? ? ? ? ·利用js讓按鈕在提交一次后不可用

function dosubmit(){

? ? //獲取表單提交按鈕

? ? var btnSubmit = document.getElementById("submit");

? ? //將表單提交按鈕設(shè)置為不可用紧武,這樣就可以避免用戶再次點(diǎn)擊提交按鈕

? ? btnSubmit.disabled= "disabled";

? ? //返回true讓表單可以正常提交

? ? return true;

}

? ? ? ? · 在session域中生成并保存唯一token,在頁面中加入隱藏域存儲token刁岸,提交時進(jìn)行檢驗(yàn)

//用戶訪問服務(wù)器

@WebServlet("/ForwardServlet")

public class ForwardServlet extends HttpServlet {

@Override

????protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

????????req.getSession().setAttribute("sesionToken", TokenUtils.getToken());

????????req.getRequestDispatcher("form.jsp").forward(req, resp);

????}

}

//跳轉(zhuǎn)頁面

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<title>Form表單</title>

</head>

????<body>

????????<form action="${pageContext.request.contextPath}/DoFormServlet"? method="post" onsubmit="return dosubmit()">

????????????<input type="hidden" name="token" value="${sesionToken}"> 用戶名:<input type="text"

????????????????name="userName"> <input type="submit" value="提交" id="submit">

????????</form>

????</body>

</html>

//服務(wù)器后端處理

HttpSession session = request.getSession();

String sesionToken = (String) session.getAttribute("sesionToken");

String token = request.getParameter("token");

if (!(token.equals(sesionToken))) {

return false;

}

session.removeAttribute("sesionToken");

3.11 Token

? ? 隨機(jī)性令牌脏里,唯一不重復(fù)字符串。

? ? 生成方式:

? ? ? ? ? ? · 自定義唯一識別碼

? ? ? ? ? ? · UUID.randomUUID().toString()

3.12 Web安全與攻防

(1)XSS 跨站腳本注入

? ? ? ? 利用Filter進(jìn)行攔截虹曙,例如將<script>轉(zhuǎn)化為html元素 &lt;script&gt;迫横。

(2)CSRF 跨站請求偽造,避免Cookie酝碳,利用token矾踱。

(3)上傳漏洞、可執(zhí)行exe文件疏哗。

(4)Sql注入 利用#{}和?占位符解決呛讲,避免sql語句的拼接。

4 HTTP

4.1 簡介

? ? 超文本傳輸協(xié)議返奉,是瀏覽器個服務(wù)端之間數(shù)據(jù)傳輸?shù)母袷揭?guī)范贝搁。HTTP使用TCP作為傳輸層協(xié)議,但HTTP本身是無連接芽偏、無狀態(tài)的雷逆,可以短連接(Http/1.0),也可以長連接(Http/1.1 保持一段時間)污尉。

4.2 Http請求

4.2.1 請求格式

GET /day09/hello?HTTP/1.1? -請求行

Host: localhost:8080? ? --請求頭(多個key-value對象)

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3

Accept-Encoding: gzip, deflate

Connection: keep-alive

--一個空行

name=eric&password=123456 ????????????--(可選)實(shí)體內(nèi)容

4.2.2 請求行

GET /day09/hello?HTTP/1.1

(1)請求方式

????常見的請求方式: GET 膀哲、 POST、 HEAD被碗、 TRACE某宪、 PUT、 CONNECT 锐朴、DELETE

????常用的請求方式: GET? 和 POST

? ? · GET
? ? ? ? ? ? · URL后面可以跟參數(shù)
? ? ? ? ? ? · 參數(shù)限制為1KB內(nèi)
? ? ? ? ? ? · 默認(rèn)方式兴喂,但不適合提交敏感密碼等內(nèi)容

? ? · POST
? ? ? ? ? ? · 參數(shù)在請求體中
? ? ? ? ? ? · 參數(shù)數(shù)據(jù)無限制
? ? ? ? ? ? · 適合提交敏感內(nèi)容

(2)http協(xié)議版本

????http1.0:當(dāng)前瀏覽器客戶端與服務(wù)器端建立連接之后,只能發(fā)送一次請求焚志,一次請求之后連接關(guān)閉衣迷。

????http1.1:當(dāng)前瀏覽器客戶端與服務(wù)器端建立連接之后,可以在一次連接中發(fā)送多次請求娩嚼。(基本都使用1.1)

(3)請求資源

????URL:? 統(tǒng)一資源定位符蘑险。http://localhost:8080/day09/testImg.html。只能定位互聯(lián)網(wǎng)資源岳悟。是URI 的子集佃迄。

????URI: 統(tǒng)一資源標(biāo)記符。/day09/hello贵少。用于標(biāo)記任何資源呵俏。可以是本地文件系統(tǒng)滔灶,局域網(wǎng)的資源(//192.168.14.10/myweb/index.html)普碎, 可以是互聯(lián)網(wǎng)。

4.2.3 請求頭

? ? · 多個key-value對象

? ? · 含有配置信息和cookie

4.2.4 實(shí)體內(nèi)容

? ? 僅POST方式含有(與請求頭有一個空行

4.2.5?HttpServletRequest對象

????HttpServletRequest對象作用是用于獲取請求數(shù)據(jù)录平。

????核心的API:

(1)請求行:

????????request.getMethod(); 請求方式

????????request.getRequetURI() ??/ request.getRequetURL()請求資源

????????request.getProtocol()請求http協(xié)議版本

(2)請求頭:

????????request.getHeader("名稱") ??根據(jù)請求頭獲取請求值

????????request.getHeaderNames()獲取所有的請求頭名稱

(3)實(shí)體內(nèi)容:

????????request.getInputStream()獲取實(shí)體內(nèi)容數(shù)據(jù)

????????request.getParameter("參數(shù)名"); 根據(jù)參數(shù)名獲取參數(shù)值(注意麻车,只能獲取一個值的參數(shù))

????????request.getParameterValue("參數(shù)名“)缀皱;根據(jù)參數(shù)名獲取參數(shù)值(可以獲取多個值的參數(shù))

????????request.getParameterNames();? 獲取所有參數(shù)名稱列表?

4.3 Http響應(yīng)

4.3.1 響應(yīng)格式

HTTP/1.1 200 OK? ?--響應(yīng)行

Server: Apache-Coyote/1.1? ?--響應(yīng)頭(key-vaule)

Content-Length: 24?

Date: Fri, 30 Jan 2015 01:54:57 GMT

--一個空行

this is hello servlet!!!? ? ? --實(shí)體內(nèi)容

4.3.2 響應(yīng)行

(1)http協(xié)議版本

(2)狀態(tài)碼: 服務(wù)器處理請求的結(jié)果(狀態(tài))

????????常見的狀態(tài)碼:

????????????200: ?表示請求處理完成并完美返回

????????????302: ??表示請求需要進(jìn)一步細(xì)化。 404: ??表示客戶訪問的資源找不到动猬。

????????????500: ??表示服務(wù)器的資源發(fā)送錯誤。(服務(wù)器內(nèi)部錯誤)

(3)狀態(tài)描述

4.3.3? HttpServletResponse對象

????HttpServletResponse對象修改響應(yīng)信息:

(1)響應(yīng)行:

????????response.setStatus()? 設(shè)置狀態(tài)碼

(2)響應(yīng)頭:

????????response.setHeader("name","value")? 設(shè)置響應(yīng)頭

(3)實(shí)體內(nèi)容:

????????response.getWriter().writer();? 發(fā)送字符實(shí)體內(nèi)容

????????response.getOutputStream().writer()? 發(fā)送字節(jié)實(shí)體內(nèi)容

4.4 Https

4.4.1 與Http區(qū)別

(1)https 協(xié)議需要到 ca 申請證書钮莲,一般免費(fèi)證書較少彼水,因而需要一定費(fèi)用。

(2)http 是超文本傳輸協(xié)議凤覆,信息是明文傳輸,https 則是具有安全性的 ssl 加密傳輸協(xié)議(對稱加密)叛赚。

(3)http 和 https 使用的是完全不同的連接方式澡绩,用的端口也不一樣肥卡,前者是 80步鉴,后者是 443璃哟。

(4)http 的連接很簡單随闪,是無狀態(tài)的铐伴;HTTPS 協(xié)議是由 SSL+HTTP 協(xié)議構(gòu)建的可進(jìn)行加密傳輸当宴、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議户矢,比 http 協(xié)議安全。

4.4.2 工作原理

圖4-1 https

 客戶端在使用HTTPS方式與 Web 服務(wù)器通信時有以下幾個步驟捌年。

 ⊙哟堋(1)客戶使用 https 的 URL 訪問 Web 服務(wù)器逆瑞,要求與 Web 服務(wù)器建立 SSL 連接获高。

 ∧钛怼(2)Web 服務(wù)器收到客戶端請求后摊趾,會將網(wǎng)站的證書信息(證書中包含公鑰)傳送一份給客戶端砾层。

 「嘏凇(3)客戶端的瀏覽器與 Web 服務(wù)器開始協(xié)商 SSL 連接的安全等級侨糟,也就是信息加密的等級秕重。

 ∪茉拧(4)客戶端的瀏覽器根據(jù)雙方同意的安全等級汰具,建立會話密鑰留荔,然后利用網(wǎng)站的公鑰將會話密鑰加密聚蝶,并傳送給網(wǎng)站碘勉。

 ⊙槊摇(5)Web 服務(wù)器利用自己的私鑰解密出會話密鑰胜嗓。

 〈侵荨(6)Web 服務(wù)器利用會話密鑰加密與客戶端之間的通信变过。

參考:HTTPS詳解 - 我是碼客 - 博客園

4.4.3 其他加密算法

4.4.3.1 AES

????高級加密標(biāo)準(zhǔn)(AES,Advanced Encryption Standard)為最常見的對稱加密算法(微信小程序加密傳輸就是用這個加密算法的)媚狰。對稱加密算法也就是加密和解密用相同的密鑰哈雏,具體的加密流程如下圖:

圖 4-2 AES流程

4.4.3.2 RSA

????RSA 加密算法是一種典型的非對稱加密算法裳瘪,它基于大數(shù)的因式分解數(shù)學(xué)難題彭羹,它也是應(yīng)用最廣泛的非對稱加密算法派殷。

????非對稱加密是通過兩個密鑰(公鑰-私鑰)來實(shí)現(xiàn)對數(shù)據(jù)的加密和解密的毡惜。公鑰用于加密经伙,私鑰用于解密。

圖 4-3 非對稱加密算法流程
圖 4-4 RSA加密算法流程及加密過程圖

4.4.3.3 CRC

????循環(huán)冗余校驗(yàn)(Cyclic Redundancy Check, CRC)是一種根據(jù)網(wǎng)絡(luò)數(shù)據(jù)包或電腦文件等數(shù)據(jù)產(chǎn)生簡短固定位數(shù)校驗(yàn)碼的一種散列函數(shù),主要用來檢測或校驗(yàn)數(shù)據(jù)傳輸或者保存后可能出現(xiàn)的錯誤张弛。它是利用除法及余數(shù)的原理來作錯誤偵測的。

4.4.3.4. MD5

????MD5 常常作為文件的簽名出現(xiàn)瞒大,我們在下載文件的時候,常常會看到文件頁面上附帶一個擴(kuò)展名為.MD5 的文本或者一行字符踢械,這行字符就是就是把整個文件當(dāng)作原數(shù)據(jù)通過 MD5 計(jì)算后的值内列,我們下載文件后话瞧,可以用檢查文件 MD5 信息的軟件對下載到的文件在進(jìn)行一次計(jì)算交排。兩次結(jié)果對比就可以確保下載到文件的準(zhǔn)確性埃篓。 另一種常見用途就是網(wǎng)站敏感信息加密,比如用戶名密碼部脚,支付簽名等等委刘。隨著 https 技術(shù)的普及钱雷,現(xiàn)在的網(wǎng)站廣泛采用前臺明文傳輸?shù)胶笈_罩抗,MD5 加密(使用偏移量)的方式保護(hù)敏感數(shù)據(jù)保護(hù)站點(diǎn)和數(shù)據(jù)安全套蒂。

參考:MD5算法分析及逆向詳解_天下布武之信長的專欄-CSDN博客_md5逆向

4.5 HttpClient工具

· 需要導(dǎo)入的依賴

<dependencies>

<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->

<dependency>

????<groupId>javax.servlet</groupId>

????<artifactId>javax.servlet-api</artifactId>

????<version>3.1.0</version>

????<scope>provided</scope>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->

<dependency>

????<groupId>org.apache.httpcomponents</groupId>

????<artifactId>httpclient</artifactId>

????<version>4.3.5</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->

<dependency>

????<groupId>org.apache.commons</groupId>

????<artifactId>commons-lang3</artifactId>

????<version>3.5</version>

</dependency>

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->

<dependency>

????<groupId>com.alibaba</groupId>

????<artifactId>fastjson</artifactId>

????<version>1.2.29</version>

</dependency>

</dependencies>

· HttpClient

/**

* 發(fā)送 post請求訪問本地應(yīng)用并根據(jù)傳遞參數(shù)不同返回不同結(jié)果

*/

public void post() {

????// 創(chuàng)建默認(rèn)的httpClient實(shí)例.

????CloseableHttpClient httpclient = HttpClients.createDefault();

????// 創(chuàng)建httppost

????HttpPost httppost = new HttpPost("http://localhost:8080/myDemo/Ajax/serivceJ.action");

????// 創(chuàng)建參數(shù)隊(duì)列

????List<NameValuePair> formparams = new ArrayList<NameValuePair>();

????formparams.add(new BasicNameValuePair("type", "house"));

????UrlEncodedFormEntity uefEntity;

????try {

????????uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");

????????httppost.setEntity(uefEntity);

????????System.out.println("executing request " + httppost.getURI());

????????CloseableHttpResponse response = httpclient.execute(httppost);

? ? ? ? try {

????????????HttpEntity entity = response.getEntity();

????????????if (entity != null) {

????????????System.out.println("--------------------------------------");

????????????System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));

????????????System.out.println("--------------------------------------");

????????????}

???????} finally {

????????????response.close();

? ? ????}

????} catch (ClientProtocolException e) {

????????e.printStackTrace();

????} catch (UnsupportedEncodingException e1) {

????????e1.printStackTrace();

????} catch (IOException e) {

????????e.printStackTrace();

????} finally {

????????// 關(guān)閉連接,釋放資源

????????????try {

????????????????httpclient.close();

? ? ? ? ? ? ? } catch (IOException e) {

????????????????????e.printStackTrace();

????????????????}

????}

}

/**

* 發(fā)送 get請求

*/

public void get() {

????CloseableHttpClient httpclient = HttpClients.createDefault();

????try {

????????// 創(chuàng)建httpget.

????????HttpGet httpget = new HttpGet("http://www.baidu.com/");

????????System.out.println("executing request " + httpget.getURI());

????????// 執(zhí)行g(shù)et請求.

????????CloseableHttpResponse response = httpclient.execute(httpget);

????????try {

????????????// 獲取響應(yīng)實(shí)體

????????????HttpEntity entity = response.getEntity();

????????????System.out.println("--------------------------------------");

????????????// 打印響應(yīng)狀態(tài)

????????????System.out.println(response.getStatusLine());

????????????if (entity != null) {

????????????????// 打印響應(yīng)內(nèi)容長度

????????????????System.out.println("Response content length: " + entity.getContentLength());

????????????????// 打印響應(yīng)內(nèi)容

????????????????System.out.println("Response content: " + EntityUtils.toString(entity));

????????????}

????????????System.out.println("------------------------------------");

????????} finally {

????????????response.close();

????????}

????} catch (ClientProtocolException e) {

????????e.printStackTrace();

????} catch (ParseException e) {

????????e.printStackTrace();

????} catch (IOException e) {

????????e.printStackTrace();

????} finally {

????????// 關(guān)閉連接,釋放資源

????????try {

????????????httpclient.close();

????????????} catch (IOException e) {

????????????????e.printStackTrace();

????????}

????}

}

4.6 跨域解決方案

(1)ajax + 響應(yīng)頭 Access-control-Allow-origin

? ??????在當(dāng)前域名請求網(wǎng)站中撼嗓,默認(rèn)不允許通過ajax請求發(fā)送其他域名且警。報(bào)錯XMLHttpRequest cannot load 斑芜。

$.ajax({

????????type : 'post',

????????dataType : "text",

????????url : "http://a.a.com/a/FromUserServlet",

????????data : "userName=余勝軍&userAge=19",

????????success : function(msg) {

????????alert(msg);

????????}

});

????????后臺response添加header,response.setHeader("Access-Control-Allow-Origin", "*"); 支持所有網(wǎng)站

(2)JSONP

? ? ? ? 在ajax中加入JSONP格式傳輸醇王。

$.ajax({

????type : "POST",

????async : false,

????url : "http://a.a.com/a/FromUserServlet?userName=張三",

????dataType : "jsonp",//數(shù)據(jù)類型為jsonp?

????jsonp : "jsonpCallback",//服務(wù)端用于接收callback調(diào)用的function名的參數(shù)?

????success : function(data) {

????????alert(data.result);

????},

????error : function() {

????????alert('fail');

????}

});

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

????resp.setCharacterEncoding("UTF-8");

????// resp.setHeader("Access-Control-Allow-Origin", "*");

????String userName = req.getParameter("userName");

????String userAge = req.getParameter("userAge");

????System.out.println(userName + "----" + userAge+"---"+req.getMethod());

????try {

????????resp.setContentType("text/plain");

????????resp.setHeader("Pragma", "No-cache");

????????resp.setHeader("Cache-Control", "no-cache");

????????resp.setDateHeader("Expires", 0);

????????PrintWriter out = resp.getWriter();

????????JSONObject resultJSON = new JSONObject(); // 根據(jù)需要拼裝json

????????resultJSON.put("result", "content");

????????String jsonpCallback = req.getParameter("jsonpCallback");// 客戶端請求參數(shù)

????????out.println(jsonpCallback + "(" + resultJSON.toJSONString() + ")");// 返回jsonp格式數(shù)據(jù)

????????out.flush();

????????out.close();

????} catch (Exception e) {

????????// TODO: handle exception

????}

}

· 注意事項(xiàng)

? ? · 原理是,底層生成一個get請求發(fā)送根暑。
? ? · 缺點(diǎn):只支持get請求排嫌,不支持post請求

(3)網(wǎng)關(guān)系統(tǒng)

? ? ? ? 使用nginx進(jìn)行域名轉(zhuǎn)發(fā)

(4)使用后臺服務(wù)器轉(zhuǎn)發(fā)淳地,如HttpClient

? ? ? ? 不建議使用颇象,非常占寬帶遣钳。

5 單點(diǎn)登錄SSO

5.1 概念

????SSO英文全稱Single Sign On劝评,單點(diǎn)登錄蒋畜。SSO是在多個應(yīng)用系統(tǒng)中姻成,用戶只需要登錄一次就可以訪問所有相互信任的應(yīng)用系統(tǒng)佣渴。

例如訪問在網(wǎng)易賬號中心(http://reg.163.com/)登錄之后,訪問以下站點(diǎn)都是登錄狀態(tài):

· 網(wǎng)易直播http://v.163.com

· 網(wǎng)易博客http://blog.163.com

· 網(wǎng)易花田http://love.163.com

· 網(wǎng)易考拉https://www.kaola.com

· 網(wǎng)易Lofterhttp://www.lofter.com

5.2 架構(gòu)

圖 5-1 SSO單點(diǎn)登錄

(1)架構(gòu)說明

· 前臺站點(diǎn):需要登錄的站點(diǎn)

· SSO站點(diǎn)-登錄:提供登錄的頁面

· SSO站點(diǎn)-登出:提供注銷登錄的入口

· SSO服務(wù)-登出:提供登錄服務(wù)

· SSO服務(wù)-登錄狀態(tài):提供登錄狀態(tài)校驗(yàn)/登錄信息查詢的服務(wù)

· SSO服務(wù)-登出:提供用戶注銷登錄的服務(wù)

· 數(shù)據(jù)庫:存儲用戶賬戶信息

· 緩存:存儲用戶的登錄信息,通常使用Redis

·用戶登錄狀態(tài)的存儲和校驗(yàn)邏輯

(2)用戶登錄狀態(tài)的存儲和校驗(yàn)

????常見的Web框架對于Seesion的實(shí)現(xiàn)都是生成一個SessionId存儲在瀏覽器Cookie中鹃答。然后將Session內(nèi)容存儲在服務(wù)器端內(nèi)存中测摔。

????用戶登錄成功之后,生成AuthToken交給客戶端保存挟纱。如果是瀏覽器紊服,就保存在Cookie中欺嗤。如果是手機(jī)App就保存在App本地緩存中煎饼。 用戶在瀏覽需要登錄的頁面時腺占,客戶端將AuthToken提交給SSO服務(wù)校驗(yàn)登錄狀態(tài)/獲取用戶登錄信息

????對于登錄信息的存儲铡羡,建議采用Redis烦周,使用Redis集群來存儲登錄信息读慎,既可以保證高可用夭委,又可以線性擴(kuò)充株灸。同時也可以讓SSO服務(wù)滿足負(fù)載均衡/可伸縮的需求。

????AuthToken屹蚊,直接使用UUID/GUID即可汹粤,如果有驗(yàn)證AuthToken合法性需求玄括,可以將UserName+時間戳加密生成遭京,服務(wù)端解密之后驗(yàn)證合法性

5.3 用戶登錄

圖 5-2 登錄時序

按照上圖船殉,用戶登錄后Authtoken保存在Cookie中利虫。 domian= test. com瀏覽器會將domain設(shè)置成 .test.com糠惫,這樣訪問所有*.test.com的web站點(diǎn)硼讽,都會將Authtoken攜帶到服務(wù)器端。然后通過SSO服務(wù)备燃,完成對用戶狀態(tài)的校驗(yàn)/用戶登錄信息的獲取并齐。

5.4 登錄信息獲取/登錄狀態(tài)校驗(yàn):

圖 5-3 登錄信息獲取/登錄狀態(tài)校驗(yàn)??

5.5 用戶登出時序圖

用戶登出時要做的事情很簡單:

· 服務(wù)端清除緩存(Redis)中的登錄狀態(tài)

· 客戶端清除存儲的AuthToken

圖 5-4用戶登出時序

5.6 跨域登錄/登出

????跨域要解決的問題,就是如何解決Cookie的跨域讀寫問題麻掸。

????解決跨域的核心思路就是:

· 登錄完成之后通過回調(diào)的方式脊奋,將AuthToken傳遞給主域名之外的站點(diǎn)膊存,該站點(diǎn)自行將AuthToken保存在當(dāng)前域下的Cookie中久又。

· 登出完成之后通過回調(diào)的方式,調(diào)用非主域名站點(diǎn)的登出頁面畏妖,完成設(shè)置Cookie中的AuthToken過期的操作。

·跨域登錄(主域名已登錄)

圖 5-5 跨域登錄(主域名已登錄)??

·跨域登錄(主域名未登錄)

圖 5-6 跨域登錄(主域名未登錄)

·跨域登出

圖 5-7跨域登出

5.7 實(shí)現(xiàn)

03-shiro權(quán)限系統(tǒng)-單點(diǎn)登陸 - 簡書

6 常見問題總結(jié)

6.1?eclipse 開發(fā)web程序

????啟動tomcat服務(wù)器的時候。臨時目錄在你的工作區(qū)間workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\

? ? 用于臨時存放服務(wù)器編譯過后的jsp、servlet敬尺、字節(jié)碼文件砂吞、圖片之類的蜻直,相當(dāng)于緩存,不用每次都編譯赎瑰,提高速度餐曼。

6.2?Servlet里resp.getWriter().write("\n")不能換行

? ? servlet編程的時候使用 resp.getWriter().write("\n") 來換行源譬,一開始還覺得代碼沒有問題呀,也沒報(bào)錯养渴,太天真了厚脉,原來是要用html標(biāo)簽來換行傻工。

????使用resp.getWriter().write("< br/>") 完全ok鸯匹,不然resp.setContentType(“text/html”)是擺在那里吃素的嗎E古睢H咎肖粮!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市尔苦,隨后出現(xiàn)的幾起案子涩馆,更是在濱河造成了極大的恐慌,老刑警劉巖允坚,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魂那,死亡現(xiàn)場離奇詭異稠项,居然都是意外死亡涯雅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門展运,熙熙樓的掌柜王于貴愁眉苦臉地迎上來斩芭,“玉大人,你說我怎么就攤上這事乐疆。” “怎么了贬养?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵挤土,是天一觀的道長。 經(jīng)常有香客問我误算,道長仰美,這世上最難降的妖魔是什么迷殿? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮咖杂,結(jié)果婚禮上庆寺,老公的妹妹穿的比我還像新娘。我一直安慰自己诉字,他們只是感情好懦尝,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著壤圃,像睡著了一般陵霉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上伍绳,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天踊挠,我揣著相機(jī)與錄音,去河邊找鬼冲杀。 笑死效床,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的权谁。 我是一名探鬼主播剩檀,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼闯传!你這毒婦竟也來了谨朝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤甥绿,失蹤者是張志新(化名)和其女友劉穎字币,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體共缕,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洗出,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了图谷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翩活。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖便贵,靈堂內(nèi)的尸體忽然破棺而出菠镇,到底是詐尸還是另有隱情,我是刑警寧澤承璃,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布利耍,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隘梨。R本人自食惡果不足惜程癌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轴猎。 院中可真熱鬧嵌莉,春花似錦、人聲如沸捻脖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽郎仆。三九已至只祠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扰肌,已是汗流浹背抛寝。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留曙旭,地道東北人盗舰。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像桂躏,于是被迫代替她去往敵國和親钻趋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348