「造個輪子」——設計 HTTP 請求全局上下文

来源:https://www.cnblogs.com/crossoverJie/archive/2018/10/09/9758178.html
-Advertisement-
Play Games

本次 Cicada 已經更新到了 v1.0.3。 主要是解決了兩個 issue,#9(Boss線程數好像設置有誤 ) #8(怎麼返回純字元串內容不要JSON格式?)。 ...


前言

本次 Cicada 已經更新到了 v1.0.3

主要是解決了兩個 issue,#9(Boss線程數好像設置有誤 ) #8(怎麼返回純字元串內容不要JSON格式?)

所以本次的主要更新為:

  • Cicada 採用合理的線程分配來處理接入請求線程以及 IO 線程。
  • 支持多種響應方式(以前只有 json,現在支持 text)。
  • 為了滿足上者引入了 context
  • 優雅停機。

其中我覺得最核心也最有用的就是這個 Context,併為此重構了大部分代碼。

多種響應方式

在起初 Cicada 預設只能響應 json,這一點確實不夠靈活。加上後續也打算支持模板解析,所以不如直接在 API 中加入可讓用戶自行選擇不同的響應方式。

因此調整後的 API 如下。

想要輸出 text/plain 時。

@CicadaAction("textAction")
public class TextAction implements WorkAction {
    @Override
    public void execute(CicadaContext context, Param param) throws Exception {
        String url = context.request().getUrl();
        String method = context.request().getMethod();
        context.text("hello world url=" + url + " method=" + method);
    }
}

而響應輸出 application/json 時只需要把需要響應的對象寫入到 json() 方法中.

因此原有的業務 action 中也加入了一個上下文的參數:

/**
 * abstract execute method
 * @param context current context
 * @param param request params
 * @throws Exception throw exception
 */
void execute(CicadaContext context ,Param param) throws Exception;

下麵就來看看這個 Context 是如何完成的。

Cicada Context

先看看有了這個上下文之後可以做什麼。

比如有些場景下我們需要拿到本次請求中的頭信息,這時就可以通過這個 Context 對象直接獲取。

當然不止是頭信息:

  • 獲取請求頭。
  • 設置響應頭。
  • 設置 cookie
  • 獲取請求 URL
  • 獲取請求的 method(get/post)等。

其實通過這些特點可以看出這些信息其實都和一次 請求、響應 密切相關,並且各個請求之間的信息應互不影響。

這樣的特性是不是非常熟悉,沒錯那就是 ThreadLocal,它可以將每個線程的信息存儲起來互不影響。

ThreadLocal 的原理本次不做過多分析,只談它在 Cicada 中的應用。

CicadaContext.class

先來看看 CicadaContext 這個類的主要成員變數以及方法。

成員變數是兩個介面 CicadaRequest、CicadaResponse,名稱就能看出肯定是存放請求和響應數據的。

HttpDispatcher.class

想要存放本次請求的上下文自然是在真正請求分發的地方 HttpDispatcher

這裡改的較大的就是兩個紅框處,第一部分是做上下文初始化及賦值。

第二部分自然就是卸載上下文。

先看初始化。

CicadaRequest cicadaRequest = CicadaHttpRequest.init(defaultHttpRequest) ;

首先是將 request 初始化:

CicadaHttpRequest 自然是實現了 CicadaRequest 介面:

這裡只保存了請求的 URL、method 等信息,後續要加的請求頭也存放在此處即可。

Response 也是同理的。

這兩個具體的實現類都私有化了構造函數,防止外部破壞了整體性。

接著將當前請求的上下文保存到了 CicadaContext 中。

CicadaContext.setContext(new CicadaContext(cicadaRequest,cicadaResponse));

而這個函數本質使用的則是 ThreadLocal 來存放 CicadaContext

    public static void setContext(CicadaContext context){
        ThreadLocalHolder.setCicadaContext(context) ;
    }
    
    private static final ThreadLocal<CicadaContext> CICADA_CONTEXT= new ThreadLocal() ;
    
    /**
     * set cicada context
     * @param context current context
     */
    public static void setCicadaContext(CicadaContext context){
        CICADA_CONTEXT.set(context) ;
    }

處理業務及響應

接著就是處理業務,調用不同的 API 做不同響應。

context.text() 來說:

其實就是設置了對應的響應方式、以及把響應內容寫入了 CicadaResponsehttpContent 中。

業務處理完後調用 responseContent() 進行響應:

responseContent(ctx,CicadaContext.getResponse().getHttpContent());

其實就是在上下文中拿到的響應方式及響應內容返回給客戶端。

卸載上下文

最後有點非常重要,那就是 卸載上下文

如果這裡不做處理,之後隨著請求的增多,ThreadLocal 里存放的數據也越來越多,最終肯定會導致記憶體溢出。

所以 CicadaContext.removeContext() 就是為了及時刪除當前上下文。

優雅停機

最後還新增了一個停機的方法。

其實也就是利用 Hook 函數實現的。

由於目前 Cicada 開的線程,占用的資源都不是特別多,所以只是關閉了 Netty 所使用的線程。

如果後續新增了自身的線程等資源,那也可以全部放到這裡來進行釋放。

總結

Cicada 已經更新了 4 個版本,雛形都有了。

後續會重點實現模板解析和註解請求路由完成,把 MVC 中的 view 完成就差不多了。

還沒有瞭解的朋友可以點擊下麵鏈接進入主頁瞭解下

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文長度為3426字,預計讀完需1.2MB流量,建議閱讀9分鐘。 閱讀目錄 「負載均衡」是什麼? 常用「負載均衡」策略圖解 常用「負載均衡」策略優缺點和適用場景 用「健康探測」來保障高可用 結語 「負載均衡」是什麼? 常用「負載均衡」策略圖解 常用「負載均衡」策略優缺點和適用場景 用「健康探測」來保 ...
  • Kafka 應對場景:消息持久化、吞吐量是第一要求、狀態由客戶端維護、必須是分散式的。Kafka 認為 broker 不應該阻塞生產者,高效的磁碟順序讀寫能夠和網路 IO 一樣快,同時依賴現代 OS 文件系統特性,寫入持久化文件時並不調用 flush,僅寫入 OS pagecache,後續由 OS ...
  • 題意 "題目鏈接" Sol 比較套路的一個題。 第一問二分答案check一下 第二問設$f[i][j]$表示前$i$個數,切了$j$段的方案數,單調隊列優化一下。 轉移的時候只需要保證當前段的長度小於最大限度即可。 cpp include using namespace std; const int ...
  • Mybatis Mybatis的介紹 1. Mybatis是持久層層框架,是半ORM(對象關係映射)框架. 2. 使用Mybatis有兩類配置文件 核心配置文件: mybatis Config.xml 映射配置文件: 與介面相對應的xml文件 3. 核心的API: SqlSessionFactory ...
  • 網路編程 bind函數 bind的作用是確定埠號。 正常處理都是先bind,然後listen 如果不bind,直接listen,會是什麼結果? 內核會自動隨機分配一個埠號 例子: c++ include include include include include include void p ...
  • 題意 "題目鏈接" Sol 挺顯然的樹形背包吧。。 $f[i][j]$表示$i$這棵子樹中答案為$j$的最大價值,轉移的時候背包一下。。 第一次寫樹形背包,犯了兩個錯誤 1. 枚舉根節點的貢獻時需要倒著枚舉 2. 轉移時需要註意$k = 0$的情況,不要出現重覆轉移 ...
  • 線上學習: [撩課-JavaWeb系列1之基礎語法-前端基礎][撩課-JavaWeb系列2之XML][撩課-JavaWeb系列3之MySQL][撩課-JavaWeb系列4之JDBC][撩課-JavaWeb系列5之web伺服器-idea] 一、字元集的由來 二、ASSCII 三、unicode 四、U ...
  • 有很多種,比如: 1、通過@RequestParam註解接收請求參數; 2、通過Bean封裝,接收多個請求參數 3、通過@ModelAttribute綁定接收前端表單數據 4、通過@PathVariable獲取URL中某段可變值; 5、通過@RequestBody接收請求體中的數據 6、通過@Req ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...