自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web-7-深入理解Cookie與Session:實(shí)現(xiàn)用戶跟蹤和數(shù)據(jù)存儲(chǔ)

開發(fā) 前端
HTTP協(xié)議是無(wú)狀態(tài)協(xié)議,每次同一瀏覽器向服務(wù)器請(qǐng)求時(shí),服務(wù)器都會(huì)將該請(qǐng)求視為新的請(qǐng)求,因此我們需要會(huì)話跟蹤技術(shù)來(lái)實(shí)現(xiàn)同一會(huì)話內(nèi)數(shù)據(jù)共享.

深入理解Cookie與Session:實(shí)現(xiàn)用戶跟蹤和數(shù)據(jù)存儲(chǔ)

今日目標(biāo)

掌握客戶端會(huì)話跟蹤技術(shù)Cookie

掌握服務(wù)端會(huì)話跟蹤技術(shù)Sesssion

一、會(huì)話跟蹤技術(shù)介紹

會(huì)話用戶打開瀏覽器,訪問(wèn)web服務(wù)器的資源,會(huì)話建立,直到有一方斷開連接,會(huì)話結(jié)束。一次會(huì)話中可以包含多次請(qǐng)求和響應(yīng)。

HTTP協(xié)議是無(wú)狀態(tài)協(xié)議,每次同一瀏覽器向服務(wù)器請(qǐng)求時(shí),服務(wù)器都會(huì)將該請(qǐng)求視為新的請(qǐng)求,因此我們需要會(huì)話跟蹤技術(shù)來(lái)實(shí)現(xiàn)同一會(huì)話內(nèi)數(shù)據(jù)共享

思考:下圖建立幾個(gè)會(huì)話?

每個(gè)瀏覽器都會(huì)與服務(wù)端建立了一個(gè)會(huì)話,加起來(lái)總共是3個(gè)會(huì)話。

思考:服務(wù)器如何識(shí)別多次請(qǐng)求是否來(lái)自于同一瀏覽器?這就需要我們學(xué)習(xí)今天的內(nèi)容,會(huì)話跟蹤技術(shù)。

會(huì)話跟蹤:一種維護(hù)瀏覽器狀態(tài)的方法,服務(wù)器需要識(shí)別多次請(qǐng)求是否來(lái)自于同一瀏覽器,以便在同一次會(huì)話的多次請(qǐng)求間共享數(shù)據(jù)

原因:HTTP協(xié)議是無(wú)狀態(tài)的,每次瀏覽器向服務(wù)器請(qǐng)求時(shí),服務(wù)器都會(huì)將該請(qǐng)求視為新的請(qǐng)求,因此我們需要會(huì)話跟蹤技術(shù)來(lái)實(shí)現(xiàn)會(huì)話內(nèi)數(shù)據(jù)共享

思考:一個(gè)會(huì)話中的多次請(qǐng)求為什么要共享數(shù)據(jù)呢?有了這個(gè)數(shù)據(jù)共享功能后能實(shí)現(xiàn)哪些功能呢?

購(gòu)物車功能: 加入購(gòu)物車和去購(gòu)物車結(jié)算是兩次請(qǐng)求,但是后面這次請(qǐng)求要想展示前一次請(qǐng)求所添加的商品,就需要用到數(shù)據(jù)共享。

記住我功能:當(dāng)用戶登錄成功后,勾選記住我按鈕后下次再登錄的時(shí)候,網(wǎng)站就會(huì)自動(dòng)填充用戶名和密碼,簡(jiǎn)化用戶的登錄操作,多次登錄就會(huì)有多次請(qǐng)求,他們之間也涉及到共享數(shù)據(jù)

實(shí)現(xiàn)方式:

  • 客戶端會(huì)話跟蹤技術(shù):Cookie。
  • 服務(wù)端會(huì)話跟蹤技術(shù):Session。

二、Cookie基本使用

Cookie:客戶端會(huì)話跟蹤技術(shù),將數(shù)據(jù)保存到客戶端,以后每次請(qǐng)求都攜帶Cookie數(shù)據(jù)進(jìn)行訪問(wèn)

1、基本使用

(1)發(fā)送Cookie

  • 創(chuàng)建Cookie對(duì)象,設(shè)置數(shù)據(jù)。
Cookie cookie = new Cookie("key","value");
  • 發(fā)送Cookie到客戶端:使用response對(duì)象。
response.addCookie(cookie);

(2)獲取Cookie

  • 獲取客戶端攜帶的所有Cookie,使用request對(duì)象。
Cookie[] cookies = request.getCookies();
  • 遍歷數(shù)組,獲取每一個(gè)Cookie對(duì)象:for。
  • 使用Cookie對(duì)象方法獲取數(shù)據(jù)。
cookie.getName();
cookie.getValue();

2、代碼實(shí)現(xiàn)

  • 創(chuàng)建08_Cookie_Session的Maven Web項(xiàng)目,并添加Servlet依賴在Pom.xml中。
<dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
Cookie[] cookies = request.getCookies();
  • 創(chuàng)建AServlet用于發(fā)送Cookie到瀏覽器。
package com.zbbmeta.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
 * 發(fā)送Cookie
 */
@WebServlet(value = "/a")
public class Aservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //1.創(chuàng)建cookie對(duì)象
        Cookie cookie = new Cookie("name","lisi");

        //2.發(fā)送cookie對(duì)象到瀏覽器
        response.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • 創(chuàng)建BServlet用于獲取Cookie數(shù)據(jù)。
package com.zbbmeta.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 獲取Cookie
 */
@WebServlet(value = "/b")
public class Bservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //3.獲取客戶端攜帶的所有Cookie,使用request對(duì)象
        Cookie[] cookies = request.getCookies();
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if(cookies!=null){
            //4.遍歷數(shù)組,獲取每一個(gè)Cookie對(duì)象:for
            for (Cookie cookie : cookies) {
                //5.使用Cookie對(duì)象方法獲取數(shù)據(jù)
                String name = cookie.getName();
                String value = cookie.getValue();
                writer.write(name+" = "+value+"<br>");
            }
        }else {

            writer.write("cookie不存在<br>");
        }

    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • 瀏覽器中先訪問(wèn)地址:http://localhost:8080/cookie-session/a,然后在訪問(wèn)http://localhost:8080/cookie-session/b查看瀏覽器結(jié)果,如圖所示:

三、Cookie原理

Cookie的實(shí)現(xiàn)是基于HTTP協(xié)議的。

  • 響應(yīng)頭:set-cookie。
  • 請(qǐng)求頭:cookie。

在瀏覽器 查看Cookie。

1、Cookie使用細(xì)節(jié) 3.1Cookie 存活時(shí)間

  • 默認(rèn)情況下,Cookie 存儲(chǔ)在瀏覽器內(nèi)存中,當(dāng)瀏覽器關(guān)閉,內(nèi)存釋放,則Cookie被銷毀。
  • setMaxAge(int seconds):設(shè)置Cookie存活時(shí)間,但是是秒 負(fù)數(shù):默認(rèn)值,Cookie在當(dāng)前瀏覽器內(nèi)存中,當(dāng)瀏覽器關(guān)閉,則 Cookie被銷毀 正數(shù):將 Cookie寫入瀏覽器所在電腦的硬盤,持久化存儲(chǔ)。到時(shí)間自動(dòng)刪除。

  • 零:立即過(guò)期,步驟和結(jié)果和正數(shù)步驟一致,這里就不掩飾了 完整代碼:
  • AServlet。
package com.zbbmeta.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
/**
 * 發(fā)送Cookie
 */
@WebServlet(value = "/a")
public class Aservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //1.創(chuàng)建cookie對(duì)象
        Cookie cookie = new Cookie("name","lisi");
        //3. setMaxAge(int seconds):設(shè)置Cookie存活時(shí)間,但是是秒
        cookie.setMaxAge(10);
//        cookie.setMaxAge(-1);
        //cookie.setMaxAge(0);
        //2.發(fā)送cookie對(duì)象到瀏覽器
        response.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}

2、Cookie 存儲(chǔ)問(wèn)題

  • 如需要存儲(chǔ)空格,則需要進(jìn)行轉(zhuǎn)碼:URL編碼 會(huì)出現(xiàn)問(wèn)題。

  • 解決方法

在發(fā)送cookie端進(jìn)行URL編碼。

URLEncoder.encode(name,"UTF-8");

在獲取cookie端進(jìn)行URL解碼。

value = URLDecoder.decode(name,"UTF-8");

瀏覽器顯示結(jié)果。

  • 完整代碼。
  • AServlet。
package com.zbbmeta.cookie;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * 發(fā)送Cookie
 */
@WebServlet(value = "/a")
public class Aservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //1.創(chuàng)建cookie對(duì)象
        String name = " lisi";
        name = URLEncoder.encode(name,"UTF-8");
        Cookie cookie = new Cookie("name",name);
        //3. setMaxAge(int seconds):設(shè)置Cookie存活時(shí)間,但是是秒
        cookie.setMaxAge(10);
//        cookie.setMaxAge(-1);
        //cookie.setMaxAge(0);
        //2.發(fā)送cookie對(duì)象到瀏覽器
        response.addCookie(cookie);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • BServlet
package com.zbbmeta.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

/**
 * 獲取Cookie
 */
@WebServlet(value = "/b")
public class Bservlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //3.獲取客戶端攜帶的所有Cookie,使用request對(duì)象
        Cookie[] cookies = request.getCookies();
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        if(cookies!=null){
            //4.遍歷數(shù)組,獲取每一個(gè)Cookie對(duì)象:for
            for (Cookie cookie : cookies) {
                //5.使用Cookie對(duì)象方法獲取數(shù)據(jù)
                String name = cookie.getName();
                String value = cookie.getValue();
                value = URLDecoder.decode(value,"UTF-8");
                writer.write(name+" = |"+value+"<br>");
            }
        }else {

            writer.write("cookie不存在<br>");
        }

    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • Tomcat7 Cookie 不能直接存儲(chǔ)中文,Tomcat8 Cookie可以存儲(chǔ)中文,但不能存儲(chǔ)空格

四、Session基本使用

Session:服務(wù)端會(huì)話跟蹤技術(shù):將數(shù)據(jù)保存到服務(wù)端

1、基本使用

(1)獲取Session

  • JavaEE 提供 HttpSession接口,來(lái)實(shí)現(xiàn)一次會(huì)話的多次請(qǐng)求間數(shù)據(jù)共享功能
  • 使用: 獲取Session對(duì)象
HttpSession session = request.getSession();

(2)Session對(duì)象功能

  • Session對(duì)象功能:
void setAttribute(String name, Object o)//存儲(chǔ)數(shù)據(jù)到 session 域中
   Object getAttribute(String name) //根據(jù) key,獲取值
   void removeAttribute(String name) //根據(jù) key,刪除該鍵值對(duì)

2、代碼實(shí)現(xiàn)

  • 創(chuàng)建CServlet用于存儲(chǔ)數(shù)據(jù)到Session對(duì)象。
package com.zbbmeta.session;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 1.存儲(chǔ)Session數(shù)據(jù)到服務(wù)器
 */
@WebServlet(value = "/c")
public class CServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //1.獲取Session對(duì)象
        HttpSession session = request.getSession();
        //2.存儲(chǔ)數(shù)據(jù)到session
        session.setAttribute("name","session_wangwu");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();

        writer.write("訪問(wèn)了C資源"+"<br>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • 創(chuàng)建DServlet用于從Session對(duì)象獲取數(shù)據(jù)。
package com.zbbmeta.session;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 2.在Session對(duì)象中獲取數(shù)據(jù)
 */
@WebServlet(value = "/d")
public class DServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        //1.獲取Session對(duì)象
        HttpSession session = request.getSession();
        //2.存儲(chǔ)數(shù)據(jù)到session
        Object name = session.getAttribute("name");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write("訪問(wèn)了D資源"+"<br>");
        if(name!=null){
            writer.write(name.toString()+"<br>");
        }else {
            writer.write("Session數(shù)據(jù)不存在"+"<br>");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • 瀏覽器中先訪問(wèn)地址:http://localhost:8080/cookie-session/c,然后在訪問(wèn)http://localhost:8080/cookie-session/d查看瀏覽器結(jié)果,如圖所示:

五、Session原理

Session基于Cookie實(shí)現(xiàn)

思考:如果新開一個(gè)瀏覽器,還是同一個(gè)session對(duì)象么?

答案:上圖顯示的獲取的Session對(duì)象不是一個(gè),每一個(gè)瀏覽器都會(huì)獲取一個(gè)新的Session對(duì)象。

  • 判斷Session對(duì)象是否是新對(duì)象代碼 CServlet。
package com.zbbmeta.session;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 1.存儲(chǔ)Session數(shù)據(jù)到服務(wù)器
 */
@WebServlet(value = "/c")
public class CServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        response.setContentType("text/html;charset=utf-8");

        PrintWriter writer = response.getWriter();
        //1.獲取Session對(duì)象
        HttpSession session = request.getSession();

        //3.判斷Session是否是新對(duì)象
        boolean aNew = session.isNew();
        //4.獲取SessionID
        String id = session.getId();
        writer.write("session 是新的= "+aNew+" session id : "+id+"<br>");

        //2.存儲(chǔ)數(shù)據(jù)到session
        session.setAttribute("name","session_wangwu");


        writer.write("訪問(wèn)了C資源"+"<br>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • DServlet
package com.zbbmeta.session;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 2.在Session對(duì)象中獲取數(shù)據(jù)
 */
@WebServlet(value = "/d")
public class DServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //get請(qǐng)求
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = response.getWriter();
        //1.獲取Session對(duì)象
        HttpSession session = request.getSession();
        //3.判斷Session是否是新對(duì)象
        boolean aNew = session.isNew();
        //4.獲取SessionID
        String id = session.getId();
        writer.write("session 是新的= "+aNew+" session id : "+id+"<br>");

        //2.存儲(chǔ)數(shù)據(jù)到session
        Object name = session.getAttribute("name");

        writer.write("訪問(wèn)了D資源"+"<br>");
        if(name!=null){
            writer.write(name.toString()+"<br>");
        }else {
            writer.write("Session數(shù)據(jù)不存在"+"<br>");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //post請(qǐng)求
        doGet(request, response);
    }
}
  • 瀏覽器結(jié)果

六、Session使用細(xì)節(jié)

1、Session 鈍化、活化

  • Session 鈍化、活化: 服務(wù)器重啟后,Session中的數(shù)據(jù)是否還在? 鈍化:在服務(wù)器正常關(guān)閉后, Tomcat自動(dòng)將 Session數(shù)據(jù)寫入硬盤的文件中活化:再次啟動(dòng)服務(wù)器后,從文件中加載數(shù)據(jù)到Session中。

在IDEA中配置鈍化

查看鈍化數(shù)據(jù)

查看鈍化數(shù)據(jù)的前臺(tái)條件是,我們已經(jīng)有Session對(duì)象存儲(chǔ)數(shù)據(jù)。

  • 我們現(xiàn)在的08_Cookie_Session項(xiàng)目啟動(dòng)的,并且訪問(wèn)了c資源。
  • 關(guān)閉項(xiàng)目。
  • 根據(jù)路徑查看session數(shù)據(jù)。
  • 發(fā)現(xiàn)有后綴為.ser的文件。
  • 重新啟動(dòng).ser文件就不存在了(步驟五就是活化)。

2、Seesion 銷毀

(1)默認(rèn)情況下,無(wú)操作,30分鐘自動(dòng)銷毀

  • 獲取存活時(shí)間方式。
//5.獲取存活時(shí)間
        int maxInactiveInterval = session.getMaxInactiveInterval();
  • 訪問(wèn)c,瀏覽器結(jié)果。

  • 停留10s,訪問(wèn)d,瀏覽器結(jié)果。

思考:為什么停留10s后,session對(duì)象的存活時(shí)間還是1800s?

存活時(shí)間表示的是沒(méi)有訪問(wèn)資源的情況下,如果訪問(wèn)了,則存活時(shí)間重新變?yōu)?800s.

(2)web.xml配置存活時(shí)間

可以通過(guò)web.xml進(jìn)行配置,單位為分鐘。

<?xml versinotallow="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 version="4.0">

 <session-config>
<!--  單位是分鐘-->
  <session-timeout>2</session-timeout>
 </session-config>
</web-app>

  • 調(diào)用 Session對(duì)象的 invalidate()方法。

注意:最好關(guān)閉瀏覽器再打開。

3、Cookie和Session的對(duì)比

  • 相同點(diǎn) Cookie 和 Session 都是來(lái)完成一次會(huì)話內(nèi)多次請(qǐng)求間數(shù)據(jù)共享的。
  • 區(qū)別 鍵值對(duì)數(shù)量:Cookie 存一個(gè)鍵和一個(gè)值,Session 存n個(gè)鍵和值存儲(chǔ)位置:Cookie 是將數(shù)據(jù)存儲(chǔ)在客戶端,Session 將數(shù)據(jù)存儲(chǔ)在服務(wù)端安全性:Cookie 不安全,Session 安全數(shù)據(jù)大?。篊ookie 最大4KB,Session 無(wú)大小限制存儲(chǔ)時(shí)間:Cookie默認(rèn)瀏覽器關(guān)閉,Session 默認(rèn)30分鐘服務(wù)器性能:Cookie 不占服務(wù)器資源,Session 占用服務(wù)器資源。
責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2021-12-09 08:09:31

Linux內(nèi)核臟頁(yè)

2017-05-04 15:36:54

Openstack Q實(shí)現(xiàn)實(shí)踐

2010-05-27 15:05:23

ServletJava

2023-11-07 00:00:00

Dialector參數(shù)接口

2024-06-28 10:25:18

2010-06-01 15:25:27

JavaCLASSPATH

2016-12-08 15:36:59

HashMap數(shù)據(jù)結(jié)構(gòu)hash函數(shù)

2020-07-21 08:26:08

SpringSecurity過(guò)濾器

2024-01-09 08:28:44

應(yīng)用多線程技術(shù)

2024-12-02 11:39:30

2019-11-07 10:37:36

CookieSessionToken

2019-06-11 14:45:25

2017-05-04 16:35:45

2010-03-12 08:55:06

Java內(nèi)省反射

2013-09-22 14:57:19

AtWood

2009-09-25 09:14:35

Hibernate日志

2023-10-19 11:12:15

Netty代碼

2021-02-17 11:25:33

前端JavaScriptthis

2020-09-23 10:00:26

Redis數(shù)據(jù)庫(kù)命令

2017-01-10 08:48:21

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)