亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Tomcat Request Cookie 丟失問題解決

 更新時間:2024年09月11日 09:00:26   作者:程序猿進(jìn)階  
生產(chǎn)環(huán)境多線程處理時偶發(fā)性出現(xiàn)前端Cookie為空告警,導(dǎo)致請求失敗,問題與Tomcat的Request復(fù)用和ThreadLocal使用缺陷有關(guān),本文就來介紹一下如何解決,感興趣的可以了解一下

一、問題描述

生產(chǎn)環(huán)境偶爾(涉及到多線程處理)出現(xiàn)"前端傳遞`Cookie為空"的告警,導(dǎo)致前端請求丟失,出現(xiàn)請求失敗問題。告警內(nèi)容如下

前端傳遞Cookie為空
告警內(nèi)容:服務(wù)端獲取request Cookie為空,請盡快處理!??!
AppId:xxxxxx
ip:xx.xx.xxx.xx
告警事件:2024-03-15

背景:為什么要加Cookie告警:項目出海,需要保證多語言,語言信息從Cookie中獲取,所以添加了Cookie告警,告警后發(fā)到工作群中,但是相關(guān)開發(fā)人員告知自己能夠正常訪問,沒有問題,因為正好周五,自己覺得偶發(fā)性肯定和并發(fā)相關(guān),所以周末研究了下代碼,發(fā)現(xiàn)和Tomcat Rquest復(fù)用機(jī)制和ThreadLocal的使用存在缺陷,導(dǎo)致這個偶發(fā)性問題

在分析原因前,先需要搞懂一個概念:requesttomcat里面是循環(huán)使用的

二、Tomcat 中 Reqeust 復(fù)用機(jī)制

Request對象的復(fù)用機(jī)制是為了提高性能和減少垃圾收集壓力而設(shè)計的。Tomcat使用了一種對象池的機(jī)制來管理Request對象和Response對象。通過復(fù)用這些對象,Tomcat可以避免頻繁地創(chuàng)建和銷毀對象,從而提高系統(tǒng)的效率。

復(fù)用機(jī)制的工作原理【1】對象池:Tomcat維護(hù)一個對象池,用于存儲Request對象和Response對象。當(dāng)一個新的HTTP請求到達(dá)時,Tomcat從對象池中獲取一個空閑的Request對象和Response對象。如果對象池中沒有空閑的對象,Tomcat會創(chuàng)建新的對象。簡單看個案例:

public class RequestPool {
    private Stack<Request> pool = new Stack<>();
    // 獲取對象:getRequest 方法從對象池中獲取一個 Request 對象。如果對象池為空,則創(chuàng)建一個新的 Request 對象。
    public Request getRequest() {
        if (pool.isEmpty()) {
            return new Request();
        } else {
            return pool.pop();
        }
    }
    // 釋放對象:releaseRequest 方法將 Request 對象重置(調(diào)用 recycle 方法)并放回對象池中。
    public void releaseRequest(Request request) {
        request.recycle();
        pool.push(request);
    }
}

【2】對象重置:當(dāng)一個請求處理完畢后,Request對象會被重置(通過調(diào)用recycle方法),以清除上一次請求的狀態(tài),使其可以安全地用于下一個請求。以下是org.apache.catalina.connector.Request類中recycle方法的簡化源碼和解釋:

public class Request {
    // Various fields representing the state of the request
    private String protocol;
    private String method;
    private String requestURI;
    private String queryString;
    private String remoteAddr;
    private String remoteHost;
    private String serverName;
    private int serverPort;
    private boolean secure;
    private InputStream inputStream;
    private Reader reader;
    private ServletInputStream servletInputStream;
    private BufferedReader bufferedReader;
    private Map<String, Object> attributes;
    private Map<String, String[]> parameters;
    private Cookie[] cookies;
    private HttpSession session;

    // Other fields and methods...

    /**
     * Recycle this request object.
     */
    public void recycle() {
        // Reset the state of the request object
        // 重置基本屬性:recycle 方法將 Request 對象的基本屬性(如 protocol、method、requestURI 等)重置為初始狀態(tài)(通常為 null 或默認(rèn)值)。
        // 清空集合和數(shù)組:attributes 和 parameters 集合被清空,以確保沒有殘留的請求數(shù)據(jù)。cookies 數(shù)組也被重置為 null。
        // 重置流和讀者:inputStream、reader、servletInputStream 和 bufferedReader 被重置為 null,以確保沒有殘留的輸入流和讀者對象。
        // 重置會話:session 被重置為 null,以確保沒有殘留的會話信息。
        protocol = null;
        method = null;
        requestURI = null;
        queryString = null;
        remoteAddr = null;
        remoteHost = null;
        serverName = null;
        serverPort = 0;
        secure = false;
        inputStream = null;
        reader = null;
        servletInputStream = null;
        bufferedReader = null;
        attributes.clear();
        parameters.clear();
        cookies = null;
        session = null;

        // Other reset logic...
    }
}

recycle執(zhí)行的時機(jī): recycle方法在Tomcat源碼中的調(diào)用時機(jī)主要是在請求處理完畢之后,Request對象被返回到對象池之前。具體來說,recycle方法通常在以下幾個場景中被調(diào)用:
【1】請求處理完畢后:在Tomcatorg.apache.coyote.Request類中,recycle方法通常在請求處理完畢后被調(diào)用。例如,在AbstractProcessorLight類中處理請求和響應(yīng)的邏輯中,recycle方法被調(diào)用來重置Request對象。

// org.apache.coyote.AbstractProcessorLight
public class AbstractProcessorLight<S> implements Processor {
    // Various fields and methods...

    @Override
    public SocketState process(SocketWrapperBase<S> socketWrapper, SocketEvent status) throws IOException {
        // Process the request and response
        try {
            // Request processing logic...
        } finally {
            // Recycle the request and response objects
            request.recycle();
            response.recycle();
        }
        return SocketState.CLOSED;
    }
}

【2】連接關(guān)閉時:在Tomcatorg.apache.coyote.http11.Http11Processor類中,當(dāng)連接關(guān)閉時,recycle方法也會被調(diào)用。例如,當(dāng)處理完一個請求并決定關(guān)閉連接時,會調(diào)用recycle方法。

// org.apache.coyote.http11.Http11Processor
public class Http11Processor extends AbstractProcessorLight<SocketChannel> {
    // Various fields and methods...

    @Override
    public SocketState service(SocketWrapperBase<SocketChannel> socketWrapper) throws IOException {
        // Service the request and response
        try {
            // Request servicing logic...
        } finally {
            // Recycle the request and response objects
            request.recycle();
            response.recycle();
        }
        return SocketState.CLOSED;
    }
}

【3】異常處理:在處理請求的過程中,如果發(fā)生異常,Tomcat也會確保調(diào)用recycle方法來重置Request對象。例如:

// org.apache.coyote.http11.Http11Processor
public class Http11Processor extends AbstractProcessorLight<SocketChannel> {
    // Various fields and methods...

    @Override
    public SocketState service(SocketWrapperBase<SocketChannel> socketWrapper) throws IOException {
        try {
            // Request servicing logic...
        } catch (Exception e) {
            // Handle exception and recycle request
            request.recycle();
            response.recycle();
            throw e;
        }
    }
}

后期原因分析中需要使用到RequestFacade,這里解釋下RequestFacadeRequest之間的關(guān)系:RequestFacade是一個包裝類Facade,用于保護(hù)底層的Request對象,確保應(yīng)用程序無法直接訪問和修改內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。

【1】Request類: Request類是Tomcat內(nèi)部用來表示HTTP請求的類,包含了請求的所有詳細(xì)信息。該類提供了許多方法來訪問和操作請求的各個部分,例如請求頭、請求參數(shù)、輸入流等。

【2】RequestFacade 類: RequestFacade類是一個包裝器,用于保護(hù)Request對象。它實(shí)現(xiàn)了javax.servlet.http.HttpServletRequest接口,并將方法調(diào)用委托給內(nèi)部的Request對象。通過使用RequestFacade,Tomcat確保了應(yīng)用程序只能通過標(biāo)準(zhǔn)的HttpServletRequest接口訪問請求數(shù)據(jù),而不能直接訪問或修改Request對象的內(nèi)部實(shí)現(xiàn)。

具體實(shí)現(xiàn):在Tomcat中,RequestFacade類通常包含一個Request對象的引用,并將所有的接口方法調(diào)用委托給這個內(nèi)部的Request對象。例如:

// org.apache.catalina.connector.RequestFacade
public class RequestFacade implements HttpServletRequest {
    private final Request request;

    public RequestFacade(Request request) {
        this.request = request;
    }

    @Override
    public String getParameter(String name) {
        return request.getParameter(name);
    }

    // Other methods from HttpServletRequest interface
    // All methods delegate to the internal Request object
}

使用場景:在Tomcat處理請求的過程中,當(dāng)需要將HttpServletRequest對象傳遞給應(yīng)用程序時,Tomcat會創(chuàng)建一個RequestFacade實(shí)例,并將內(nèi)部的Request對象傳遞給它。例如

// org.apache.catalina.connector.CoyoteAdapter
public class CoyoteAdapter implements Adapter {
    @Override
    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception {
        Request request = (Request) req.getNote(ADAPTER_NOTES);
        Response response = (Response) res.getNote(ADAPTER_NOTES);

        // Create a RequestFacade to pass to the application
        HttpServletRequest requestFacade = request.getRequest();

        // Pass the RequestFacade to the application
        context.getPipeline().getFirst().invoke(requestFacade, response);
    }
}

三、原因分析

【1】第一次請求由線程A正常執(zhí)行,執(zhí)行完成后執(zhí)行recycle方法,將RequestFacade中的屬性修改為null,準(zhǔn)備下次復(fù)用,但是當(dāng)前線程的ThreadLocal沒有被清理。

【2】第二次請求恰好也由線程A執(zhí)行(這也是偶發(fā)的原因),通過ThreadLocal獲取RequestFacade對象,并通過getCookies獲取Cookie,因為第一次請求結(jié)束后將Cookie置為null并將cookiesParsed修改為了false,但是這次請求再次調(diào)用getCookies的時候,將cookiesParsed修改為了true。用來表示RequestFacade ACookies已經(jīng)被解析過了。同時需要注意,此時第一次請求的生命周期已經(jīng)結(jié)束了,所以重置cookiesParsed的操作就不復(fù)存在了,Tomcat重新復(fù)用RequestFacade A的時候Cookies就會獲取到一個null。

@Override
public Cookie[] getCookies() {
    if (!cookiesParsed) {
        parseCookies();
    }
    return cookies;
}

protected void parseCookies() {
    cookiesParsed = true;

    Cookies serverCookies = coyoteRequest.getCookies();
    int count = serverCookies.getCookieCount();
    if (count <= 0) {
        returnl
    }

    cookies = new Cookie[count];
}

【3】第三次請求時,Tomcat復(fù)用了RequestFacade A,當(dāng)正常解析Cookies的時候發(fā)現(xiàn)cookiesParsedtrue就跳過了正確解析的環(huán)節(jié),當(dāng)需要使用Cookie的時候發(fā)現(xiàn)為空,本次請求直接被中止。(靈異事件)

解決方案:

【1】ThreadLocal使用完后一定需要clean;
【2】不要在跨線程中使用request對象??梢允褂?code>-Dorg.apache.catalina.connector.RECYCLE_FACADES=true禁止復(fù)用。在項目的extraenv.sh中設(shè)置參數(shù)后,如果有訪問已經(jīng)被回收的request對象,就會拋出The request object has been recycled and is no longer associated with this facade異常,以此就能定位到問題

到此這篇關(guān)于Tomcat Request Cookie 丟失問題解決的文章就介紹到這了,更多相關(guān)Tomcat Request Cookie 丟失內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:

相關(guān)文章

  • tomcat部署jenkins項目的實(shí)現(xiàn)示例

    tomcat部署jenkins項目的實(shí)現(xiàn)示例

    Jenkins自動化部署可以解決集成、測試、部署等重復(fù)性的工作,本文主要介紹了tomcat部署jenkins項目,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • 修改Tomcat默認(rèn)訪問根目錄的方法

    修改Tomcat默認(rèn)訪問根目錄的方法

    這篇文章主要介紹了修改Tomcat默認(rèn)訪問根目錄的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • tomcat?集群監(jiān)控與彈性伸縮詳解

    tomcat?集群監(jiān)控與彈性伸縮詳解

    這篇文章主要為大家介紹了tomcat?集群監(jiān)控與彈性伸縮詳解,
    2022-09-09
  • Tomcat實(shí)現(xiàn)熱部署

    Tomcat實(shí)現(xiàn)熱部署

    本篇文章主要介紹了Tomcat熱部署的概念、好處與實(shí)現(xiàn)方式,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • Java Tomcat 啟動閃退問題解決集

    Java Tomcat 啟動閃退問題解決集

    Tomcat 啟動時出現(xiàn)黑屏一閃而過的現(xiàn)象原因有很多,這篇文章就詳細(xì)介紹了tomcat啟動閃退問題的一些解決方法,感興趣的同學(xué)可以仔細(xì)閱讀
    2023-03-03
  • tomcat服務(wù)安裝步驟及詳細(xì)配置實(shí)戰(zhàn)教程

    tomcat服務(wù)安裝步驟及詳細(xì)配置實(shí)戰(zhàn)教程

    Tomcat是由Apache開發(fā)的一個開源Java WEB應(yīng)用服務(wù)器,下面這篇文章主要給大家介紹了關(guān)于tomcat服務(wù)安裝步驟及詳細(xì)配置實(shí)戰(zhàn)教程,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Tomcat 類加載器的實(shí)現(xiàn)方法及實(shí)例代碼

    Tomcat 類加載器的實(shí)現(xiàn)方法及實(shí)例代碼

    這篇文章主要介紹了Tomcat 類加載器的實(shí)現(xiàn)方法及實(shí)例代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-05-05
  • 解決Tomcat?Caused?by:?java.lang.ClassNotFoundException:?java.util.logging.Logger的問題

    解決Tomcat?Caused?by:?java.lang.ClassNotFoundException:?ja

    這篇文章主要給大家介紹了如何解決Tomcat?Caused?by:?java.lang.ClassNotFoundException:?java.util.logging.Logger的問題,文中有詳細(xì)的原因分析及解決方法,需要的朋友可以參考下
    2023-10-10
  • Tomcat+Mysql高并發(fā)配置優(yōu)化講解

    Tomcat+Mysql高并發(fā)配置優(yōu)化講解

    今天小編就為大家分享一篇關(guān)于Tomcat+Mysql高并發(fā)配置優(yōu)化講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • 淺談Tomcat亂碼與端口占用的解決方案

    淺談Tomcat亂碼與端口占用的解決方案

    這篇文章主要介紹了淺談Tomcat亂碼與端口占用的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11

最新評論