欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

「造个*」——设计 HTTP 请求全局上下文

程序员文章站 2022-08-21 14:50:20
本次 Cicada 已经更新到了 v1.0.3。 主要是解决了两个 issue,#9(Boss线程数好像设置有误 ) #8(怎么返回纯字符串内容不要JSON格式?)。 ......

「造个*」——设计 HTTP 请求全局上下文

前言

本次 cicada 已经更新到了 「造个*」——设计 HTTP 请求全局上下文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() 方法中.

「造个*」——设计 HTTP 请求全局上下文

因此原有的业务 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 这个类的主要成员变量以及方法。

「造个*」——设计 HTTP 请求全局上下文

成员变量是两个接口 cicadarequest、cicadaresponse,名称就能看出肯定是存放请求和响应数据的。

httpdispatcher.class

想要存放本次请求的上下文自然是在真正请求分发的地方 httpdispatcher

「造个*」——设计 HTTP 请求全局上下文

这里改的较大的就是两个红框处,第一部分是做上下文初始化及赋值。

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

先看初始化。

cicadarequest cicadarequest = cicadahttprequest.init(defaulthttprequest) ;

首先是将 request 初始化:

cicadahttprequest 自然是实现了 cicadarequest 接口:

「造个*」——设计 HTTP 请求全局上下文

这里只保存了请求的 url、method 等信息,后续要加的请求头也存放在此处即可。

response 也是同理的。

「造个*」——设计 HTTP 请求全局上下文

这两个具体的实现类都私有化了构造函数,防止外部破坏了整体性。

接着将当前请求的上下文保存到了 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() 来说:

「造个*」——设计 HTTP 请求全局上下文

其实就是设置了对应的响应方式、以及把响应内容写入了 cicadaresponsehttpcontent 中。

业务处理完后调用 responsecontent() 进行响应:

responsecontent(ctx,cicadacontext.getresponse().gethttpcontent());

其实就是在上下文中拿到的响应方式及响应内容返回给客户端。

卸载上下文

最后有点非常重要,那就是 卸载上下文

如果这里不做处理,之后随着请求的增多,threadlocal 里存放的数据也越来越多,最终肯定会导致内存溢出。

所以 cicadacontext.removecontext() 就是为了及时删除当前上下文。

优雅停机

最后还新增了一个停机的方法。

「造个*」——设计 HTTP 请求全局上下文

其实也就是利用 hook 函数实现的。

由于目前 cicada 开的线程,占用的资源都不是特别多,所以只是关闭了 netty 所使用的线程。

如果后续新增了自身的线程等资源,那也可以全部放到这里来进行释放。

总结

cicada 已经更新了 4 个版本,雏形都有了。

后续会重点实现模板解析和注解请求路由完成,把 mvc 中的 view 完成就差不多了。

还没有了解的朋友可以点击下面链接进入主页了解下