最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Tomcat Request Cookie 丟失問題解決

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

一、問題描述

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

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

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

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

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

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

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

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

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

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 對(duì)象的基本屬性(如 protocol、method、requestURI 等)重置為初始狀態(tài)(通常為 null 或默認(rèn)值)。
        // 清空集合和數(shù)組:attributes 和 parameters 集合被清空,以確保沒有殘留的請(qǐng)求數(shù)據(jù)。cookies 數(shù)組也被重置為 null。
        // 重置流和讀者:inputStream、reader、servletInputStream 和 bufferedReader 被重置為 null,以確保沒有殘留的輸入流和讀者對(duì)象。
        // 重置會(huì)話:session 被重置為 null,以確保沒有殘留的會(huì)話信息。
        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í)行的時(shí)機(jī): recycle方法在Tomcat源碼中的調(diào)用時(shí)機(jī)主要是在請(qǐng)求處理完畢之后,Request對(duì)象被返回到對(duì)象池之前。具體來說,recycle方法通常在以下幾個(gè)場(chǎng)景中被調(diào)用:
【1】請(qǐng)求處理完畢后:在Tomcatorg.apache.coyote.Request類中,recycle方法通常在請(qǐng)求處理完畢后被調(diào)用。例如,在AbstractProcessorLight類中處理請(qǐng)求和響應(yīng)的邏輯中,recycle方法被調(diào)用來重置Request對(duì)象。

// 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)閉時(shí):在Tomcatorg.apache.coyote.http11.Http11Processor類中,當(dāng)連接關(guān)閉時(shí),recycle方法也會(huì)被調(diào)用。例如,當(dāng)處理完一個(gè)請(qǐng)求并決定關(guān)閉連接時(shí),會(huì)調(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】異常處理:在處理請(qǐng)求的過程中,如果發(fā)生異常,Tomcat也會(huì)確保調(diào)用recycle方法來重置Request對(duì)象。例如:

// 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是一個(gè)包裝類Facade,用于保護(hù)底層的Request對(duì)象,確保應(yīng)用程序無法直接訪問和修改內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。

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

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

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

// 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
}

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

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

【2】第二次請(qǐng)求恰好也由線程A執(zhí)行(這也是偶發(fā)的原因),通過ThreadLocal獲取RequestFacade對(duì)象,并通過getCookies獲取Cookie,因?yàn)榈谝淮握?qǐng)求結(jié)束后將Cookie置為null并將cookiesParsed修改為了false,但是這次請(qǐng)求再次調(diào)用getCookies的時(shí)候,將cookiesParsed修改為了true。用來表示RequestFacade ACookies已經(jīng)被解析過了。同時(shí)需要注意,此時(shí)第一次請(qǐng)求的生命周期已經(jīng)結(jié)束了,所以重置cookiesParsed的操作就不復(fù)存在了,Tomcat重新復(fù)用RequestFacade A的時(shí)候Cookies就會(huì)獲取到一個(gè)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】第三次請(qǐng)求時(shí),Tomcat復(fù)用了RequestFacade A,當(dāng)正常解析Cookies的時(shí)候發(fā)現(xiàn)cookiesParsedtrue就跳過了正確解析的環(huán)節(jié),當(dāng)需要使用Cookie的時(shí)候發(fā)現(xiàn)為空,本次請(qǐng)求直接被中止。(靈異事件)

解決方案:

【1】ThreadLocal使用完后一定需要clean
【2】不要在跨線程中使用request對(duì)象。可以使用-Dorg.apache.catalina.connector.RECYCLE_FACADES=true禁止復(fù)用。在項(xiàng)目的extraenv.sh中設(shè)置參數(shù)后,如果有訪問已經(jīng)被回收的request對(duì)象,就會(huì)拋出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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

您可能感興趣的文章:

相關(guān)文章

  • 啟動(dòng)tomcat時(shí) 錯(cuò)誤: 代理拋出異常 : java.rmi.server.ExportException: Port already in use: 1099的解決辦法

    啟動(dòng)tomcat時(shí) 錯(cuò)誤: 代理拋出異常 : java.rmi.server.ExportException: Port

    這篇文章主要介紹了啟動(dòng)tomcat時(shí) 錯(cuò)誤: 代理拋出異常 : java.rmi.server.ExportException: Port already in use: 1099的解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • Tomcat?與?maven?的安裝與使用教程

    Tomcat?與?maven?的安裝與使用教程

    這篇文章主要介紹了Tomcat?與?maven?的安裝與使用,Tomcat?HTTP?服務(wù)器,按照?HTTP?協(xié)議的格式來解析請(qǐng)求,調(diào)用用戶指定的相關(guān)代碼,并且按照?HTTP?響應(yīng)的格式來構(gòu)造返回?cái)?shù)據(jù),需要的朋友可以參考下
    2022-06-06
  • 安裝tomcat后可能出現(xiàn)的問題介紹

    安裝tomcat后可能出現(xiàn)的問題介紹

    大家好,本篇文章主要講的是安裝tomcat后可能出現(xiàn)的問題介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01
  • Tomcat三種閃退問題以及解決原因和辦法詳解

    Tomcat三種閃退問題以及解決原因和辦法詳解

    這篇文章主要介紹了Tomcat三種閃退問題以及解決原因和辦法的相關(guān)資料,通過檢查和配置JAVA_HOME環(huán)境變量和驗(yàn)證JDK安裝,可以解決大部分啟動(dòng)問題,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-12-12
  • 同一臺(tái)服務(wù)器(電腦)運(yùn)行多個(gè)Tomcat的設(shè)置方法步驟

    同一臺(tái)服務(wù)器(電腦)運(yùn)行多個(gè)Tomcat的設(shè)置方法步驟

    這篇文章主要介紹了同一臺(tái)服務(wù)器(電腦)運(yùn)行多個(gè)Tomcat的設(shè)置方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-04-04
  • tomcat安裝及部署的方法實(shí)現(xiàn)

    tomcat安裝及部署的方法實(shí)現(xiàn)

    Tomcat是一個(gè)免費(fèi)、開源的javaWeb輕量級(jí)應(yīng)用服務(wù)器,本文主要介紹了tomcat安裝及部署的方法實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • Tomcat中catalina.bat設(shè)置為UTF-8控制臺(tái)出現(xiàn)亂碼

    Tomcat中catalina.bat設(shè)置為UTF-8控制臺(tái)出現(xiàn)亂碼

    這篇文章主要介紹了Tomcat中catalina.bat設(shè)置為UTF-8控制臺(tái)出現(xiàn)亂碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Tomcat 啟動(dòng)閃退常見問題18種解決方法及示例

    Tomcat 啟動(dòng)閃退常見問題18種解決方法及示例

    Tomcat啟動(dòng)閃退可能由多種原因引起,包括配置錯(cuò)誤、資源限制、兼容性問題等,本文主要介紹了Tomcat 啟動(dòng)閃退常見問題18種解決方法及示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • Tomcat錯(cuò)誤頁重定向問題

    Tomcat錯(cuò)誤頁重定向問題

    這篇文章主要介紹了Tomcat錯(cuò)誤頁重定向問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 騰訊云Ubuntu14.04安裝Tomcat8教程

    騰訊云Ubuntu14.04安裝Tomcat8教程

    本篇文章主要介紹了騰訊云Ubuntu14.04安裝Tomcat8教程,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03

最新評(píng)論

陆良县| 通河县| 手游| 甘洛县| 高雄市| 平泉县| 安化县| 独山县| 宁夏| 焦作市| 桓台县| 汉寿县| 信宜市| 陇西县| 绥江县| 滕州市| 元江| 贵港市| 乌拉特后旗| 石泉县| 湖北省| 徐水县| 田阳县| 长岭县| 紫金县| 大名县| 乐安县| 灵丘县| 防城港市| 闵行区| 犍为县| 任丘市| 平和县| 申扎县| 古蔺县| 遂昌县| 唐山市| 太仆寺旗| 布拖县| 彩票| 库伦旗|