日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Web服务必须要知道的几个概念

發布時間:2024/9/30 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Web服务必须要知道的几个概念 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. servlet基礎概念

  • 就是一個運行在WEB服務器上的小的Java程序,用來接收和響應從客戶端發送過來的請求,通常使用HTTP協議。用戶通過單擊某個鏈接或者直接在瀏覽器的地址欄中輸入URL來訪問,Web服務器接收到該請求后交給Servlet容器。Servlet容器實例化Servlet,調用Servlet的一個特定方法對請求進行處理, 并產生一個響應。這個響應由Servlet容器返回給Web服務器,Web服務器包裝這個響應,以HTTP響應的形式發送給Web瀏覽器.

  • 接口servlet ———> 通用GenericServlet ————> HttpServlet

  • servlet的生命周期

    • 何時創建:用戶第一次訪問時創建。但是可以配置在服務器啟動的時候就去創建servlet
    • 何時銷毀:當項目從服務器中移除或者關閉服務器的時候

    用戶第一次訪問Servlet的時候,服務器會創建一個Servlet的實例,那么Servlet中init方法就會執行.任何一次請求服務器都會創建一個新的線程訪問Servlet中的service的方法.在service方法內部根據請求的方式的不同調用doXXX的方法.(get請求調用doGet,post請求調用doPost).當Servlet中服務器中移除掉,或者關閉服務器,Servlet的實例就會被銷毀,那么destroy方法就會執行。

  • ServletContext是一個域對象,作用范圍是整個web工程,Servlet容器在啟動時會加載Web應用,并為每個Web應用創建唯一的ServletContext對象。它可以獲取全局初始化參數,作為域對象存取數據,讀取文件等。在springboot中可以監聽ServletContext的創建銷毀,完成項目啟動時要初始化的一些工作。

  • import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener;import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 注意還要添加@ServletComponentScan注解 */ @WebListener public class MyServletContextListener implements ServletContextListener{private Logger logger = LoggerFactory.getLogger(this.getClass());@Overridepublic void contextDestroyed(ServletContextEvent arg0) {// TODO logger.info("jun: contextDestroyed");}@Overridepublic void contextInitialized(ServletContextEvent arg0) {// TODO logger.info("jun: ServletContextInitialized");}}

    2. cookie和session

    cookie有會話級別cookie和持久級別cookie。setDomain(String domain);setPath(String path);setMaxAge(int maxAge);
    Tomcat中的Session機制

    2.1 什么是Session

    對Tomcat而言,Session是一塊在服務器開辟的內存空間,其存儲結構為ConcurrentHashMap;
    session創建:服務器第一次調用getSession()時創建。
    銷毀有三種情況:session過期,默認30分鐘;非正常關閉服務器,正常關閉會序列化到硬盤;手動調用session.invalidate()。
    作用范圍:多次請求,一次會話。

    2.2 Session的目的

    Http協議是一種無狀態協議,即每次服務端接收到客戶端的請求時,都是一個全新的請求,服務器并不知道客戶端的歷史請求記錄;
    Session的主要目的就是為了彌補Http的無狀態特性。簡單的說,就是服務器可以利用session存儲客戶端在同一個會話期間的一些操作記錄;

    2.3 實現機制

    先看兩個問題,如下:
    1、服務器如何判斷客戶端發送過來的請求是屬于同一個會話?
    答:用Session id區分,Session id相同的即認為是同一個會話,在Tomcat中Session id用JSESSIONID表示;

    2、服務器、客戶端如何獲取Session id?Session id在其之間是如何傳輸的呢? 答:服務器第一次接收到請求時,開辟了一塊Session空間(創建了Session對象),同時生成一個Session id,并通過響應頭的Set-Cookie:“JSESSIONID=XXXXXXX”命令,向客戶端發送要求設置cookie的響應;
    客戶端收到響應后,在本機客戶端設置了一個JSESSIONID=XXXXXXX的cookie信息,該cookie的過期時間為瀏覽器會話結束;
    接下來客戶端每次向同一個網站發送請求時,請求頭都會帶上該cookie信息(包含Session id);
    然后,服務器通過讀取請求頭中的Cookie信息,獲取名稱為JSESSIONID的值,得到此次請求的Session id;
    ps:服務器只會在客戶端第一次請求響應的時候,在響應頭上添加Set-Cookie:“JSESSIONID=XXXXXXX”信息,接下來在同一個會話的第二第三次響應頭里,是不會添加Set-Cookie:“JSESSIONID=XXXXXXX”信息的;
    而客戶端是會在每次請求頭的cookie中帶上JSESSIONID信息;

    舉個例子:
    以chrome瀏覽器為例,訪問一個基于tomcat服務器的網站的時候,
    瀏覽器第一次訪問服務器,服務器會在響應頭添加Set-Cookie:“JSESSIONID=XXXXXXX”信息,要求客戶端設置cookie,如下圖:

    同時我們也可以在瀏覽器中找到其存儲的sessionid信息,如下圖


    接下來,瀏覽器第二次、第三次…訪問服務器,觀察其請求頭的cookie信息,可以看到JSESSIONID信息存儲在cookie里,發送給服務器;且響應頭里沒有Set-Cookie信息,如下圖:


    只要瀏覽器未關閉,在訪問同一個站點的時候,其請求頭Cookie中的JSESSIONID都是同一個值,被服務器認為是同一個會話。
    再舉個簡單的例子加深印象,新建個Web工程,并寫一個Servlet,在doGet中添加如下代碼,主要做如下工作
    首先,從session中獲取key為count的值,累加,存入session,并打印;
    然后,每次從請求中獲取打印cookie信息,從響應中獲取打印Header的Set-Cookie信息:

    /*** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {if(request.getSession().getAttribute("count") == null){request.getSession().setAttribute("count", 0);response.getWriter().write(0+"");}else{int a = Integer.parseInt(request.getSession().getAttribute("count").toString());request.getSession().setAttribute("count", ++a);response.getWriter().write(a+"");}Cookie[] cookies = request.getCookies();StringBuffer sb = new StringBuffer();if(cookies!=null){for(Cookie cookie : cookies){sb.append(cookie.getName()+":"+cookie.getValue()+",");}sb.deleteCharAt(sb.length()-1);}System.out.println("[第"+(++index)+"次訪問]from client request, cookies:" + sb);System.out.println("[第"+(index)+"次訪問]from server response, header-Set-Cookie:" +response.getHeader("Set-Cookie"));;}

    部署到tomcat后,連續訪問該servlet,觀察控制臺輸出,如下,客戶端第一次訪問服務器的時候,在服務端的響應頭里添加了JSESSIONID信息,且接下來客戶端的每次訪問都會帶上該JSESSIONID:

    其實這里有一個問題,session劫持
    只要用戶知道JSESSIONID,該用戶就可以獲取到JSESSIONID對應的session內容,還是以上面這個例子為例,
    我先用IE瀏覽器訪問該站點,比如連續訪問了5次,此時,session中的count值為:

    查看該會話的Session id,為6A541281A79B24BC290ED3270CF15E32

    接下來打開chrome控制臺,將IE瀏覽器獲取過來的JSESSIONID信息(“6A541281A79B24BC290ED3270CF15E32”)寫入到cookie中,如下


    接著刪除其中的一個,只留下JSESSIONID為“6A541281A79B24BC290ED3270CF15E32”的cookie;

    刷新頁面,發現我們從session獲取的count值已經變成6了,說明此次chrome瀏覽器的請求劫持了IE瀏覽器會話中的session,

    2.4 Tomcat中的session實現

    Tomcat中一個會話對應一個session,其實現類是StandardSession,查看源碼,可以找到一個attributes成員屬性,即存儲session的數據結構,為ConcurrentHashMap,支持高并發的HashMap實現;

    /*** The collection of user data attributes associated with this Session.*/protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

    那么,tomcat中多個會話對應的session是由誰來維護的呢?ManagerBase類,查看其代碼,可以發現其有一個sessions成員屬性,存儲著各個會話的session信息:

    /*** The set of currently active Sessions for this Manager, keyed by* session identifier.*/protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

    接下來,看一下幾個重要的方法,

    服務器查找Session對象的方法
    客戶端每次的請求,tomcat都會在HashMap中查找對應的key為JSESSIONID的Session對象是否存在,可以查看Request的doGetSession方法源碼,如下源碼:

    protected Session doGetSession(boolean create) {// There cannot be a session if no context has been assigned yetContext context = getContext();if (context == null) {return (null);}// Return the current session if it exists and is validif ((session != null) && !session.isValid()) {session = null;}if (session != null) {return (session);}// Return the requested session if it exists and is validManager manager = context.getManager();if (manager == null) {return null; // Sessions are not supported}if (requestedSessionId != null) {try {session = manager.findSession(requestedSessionId);} catch (IOException e) {session = null;}if ((session != null) && !session.isValid()) {session = null;}if (session != null) {session.access();return (session);}}// Create a new session if requested and the response is not committedif (!create) {return (null);}if ((context != null) && (response != null) &&context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE) &&response.getResponse().isCommitted()) {throw new IllegalStateException(sm.getString("coyoteRequest.sessionCreateCommitted"));}// Re-use session IDs provided by the client in very limited// circumstances.String sessionId = getRequestedSessionId();if (requestedSessionSSL) {// If the session ID has been obtained from the SSL handshake then// use it.} else if (("/".equals(context.getSessionCookiePath())&& isRequestedSessionIdFromCookie())) {/* This is the common(ish) use case: using the same session ID with* multiple web applications on the same host. Typically this is* used by Portlet implementations. It only works if sessions are* tracked via cookies. The cookie must have a path of "/" else it* won't be provided to for requests to all web applications.** Any session ID provided by the client should be for a session* that already exists somewhere on the host. Check if the context* is configured for this to be confirmed.*/if (context.getValidateClientProvidedNewSessionId()) {boolean found = false;for (Container container : getHost().findChildren()) {Manager m = ((Context) container).getManager();if (m != null) {try {if (m.findSession(sessionId) != null) {found = true;break;}} catch (IOException e) {// Ignore. Problems with this manager will be// handled elsewhere.}}}if (!found) {sessionId = null;}sessionId = getRequestedSessionId();}} else {sessionId = null;}session = manager.createSession(sessionId);// Creating a new session cookie based on that sessionif ((session != null) && (getContext() != null)&& getContext().getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE)) {Cookie cookie =ApplicationSessionCookieConfig.createSessionCookie(context, session.getIdInternal(), isSecure());response.addSessionCookieInternal(cookie);}if (session == null) {return null;}session.access();return session;}

    先看doGetSession方法中的如下代碼,這個一般是第一次訪問的情況,即創建session對象,session的創建是調用了ManagerBase的createSession方法來實現的; 另外,注意response.addSessionCookieInternal方法,該方法的功能就是上面提到的往響應頭寫入“Set-Cookie”信息;最后,還要調用session.access方法記錄下該session的最后訪問時間,因為session是可以設置過期時間的;

    session = manager.createSession(sessionId);// Creating a new session cookie based on that sessionif ((session != null) && (getContext() != null)&& getContext().getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE)) {Cookie cookie =ApplicationSessionCookieConfig.createSessionCookie(context, session.getIdInternal(), isSecure());response.addSessionCookieInternal(cookie);}if (session == null) {return null;}session.access();return session;

    再看doGetSession方法中的如下代碼,這個一般是第二次以后訪問的情況,通過ManagerBase的findSession方法查找session,其實就是利用map的key從ConcurrentHashMap中拿取對應的value,這里的key即requestedSessionId,也即JSESSIONID,同時還要調用session.access方法,記錄下該session的最后訪問時間;

    if (requestedSessionId != null) {try {session = manager.findSession(requestedSessionId);} catch (IOException e) {session = null;}if ((session != null) && !session.isValid()) {session = null;}if (session != null) {session.access();return (session);}}

    在session對象中查找和設置key-value的方法
    這個我們一般調用getAttribute/setAttribute方法:
    getAttribute方法很簡單,就是根據key從map中獲取value;
    setAttribute方法稍微復雜點,除了設置key-value外,如果添加了一些事件監聽(HttpSessionAttributeListener)的話,還要通知執行,如beforeSessionAttributeReplaced, afterSessionAttributeReplaced, beforeSessionAttributeAdded、 afterSessionAttributeAdded。。。

    2.5 session存在的問題

    安全性,session劫持,這個前面已經舉過例子了;
    增加服務器壓力,因為session是直接存儲在服務器的內存中的;
    如果存在多臺服務器的話,還存在session同步問題,當然如果只有一臺tomcat服務器的話,也就沒有session同步的事情了,然而現在一般的應用都會用到多臺tomcat服務器,通過負載均衡,同一個會話有可能會被分配到不同的tomcat服務器,因此很可能出現session不一致問題;解決session同步問題,實際上主要是保證能夠抽離出一塊共享空間存放session信息,且這塊空間不同的tomcat服務器都可以訪問到;一般這塊共享的空間可以是數據庫(如大多數使用到redis),或者某臺服務器的內存空間,甚至硬盤空間,或者客戶端的cookie也是可以的。

    總結

    以上是生活随笔為你收集整理的Web服务必须要知道的几个概念的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。