.Net Core Web Api实践(三).net core+Redis+docker实现Session共享

前言:上篇文章介绍了.net core+Redis+IIS+nginx实现Session共享,本来打算直接说明后续填坑过程,但毕竟好多坑是用docker部署后出现的,原计划简单提一下.net core+Redis+docker实现Session共享,但是发现篇幅也不小,所以还是单独起草一篇,除了k8s部署docker,其它部分都有基本介绍。

1、环境准备

操作系统:Windows10

VS2019、本地Redis数据库、Windows docker

2、背景介绍

由于项目从asp.net MVC向.net core webapi迁移,一方面是技术方面的迁移,另一方面是从业务方面切割,向微服务模式转型,项目最后完成部署的结构大致如下:

总体上说,大家各自的项目有各自的部署方式,一旦做成分布式的,实现Session共享往往就不可避免了。

3、.net core+Redis+docker实现Session共享

如果你的项目是用IIS或其它方式部署,那么这部分你可以直接跳过了,因为代码部分跟上篇文章是一样的。无非是使用windows docker 命令进行部署。

(1)用VS2019新建一个Web Api项目(RedisSessionTest)

在Startup.cs文件中添加以下代码  

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => false; //这里要改为false,默认是true,true的时候session无效
                options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
            });

            services.AddDataProtection(configure =>
            {
                configure.ApplicationDiscriminator = "commonweb1";
            })
            .SetApplicationName("commonweb1")
            .AddKeyManagementOptions(options =>
            {
                //配置自定义XmlRepository
                options.XmlRepository = new SessionShare();
            });

            //services.AddSession();
            #region 使用Redis保存Session
            // 这里取连接字符串
            services.AddDistributedRedisCache(option =>
            {
                //redis 连接字符串
                option.Configuration = "";
                //redis 实例名
                option.InstanceName = "Test_Session";
            });

            //添加session 设置过期时长分钟
            //var sessionOutTime = con.ConnectionConfig.ConnectionRedis.SessionTimeOut;
            services.AddSession(options =>
            {
                options.IdleTimeout = TimeSpan.FromSeconds(Convert.ToDouble(3 * 60 * 60)); //session活期时间
                options.Cookie.HttpOnly = true;//设为httponly
            });
            #endregion

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseSession();
            app.UseMiddleware<RequestMiddleware>();
            app.UseCookiePolicy();
            app.UseMvc();
        }

  

为什么这么加请参考上篇文章,这里我只做一个简单的介绍:

services.Configure<CookiePolicyOptions>:配置可以读取cookie信息。

app.UseCookiePolicy():表示使用ConfigureServices中配置cookie策略

services.AddDataProtection:配置应用程序名称,自定义MachineKey,用于不同站点服务可以读取同一Session。

services.AddDistributedRedisCache:将Session保存到Redis数据库。

services.AddSession:配置Sesion策略。

app.UseMiddleware<RequestMiddleware>():使用自定义中间件。

(2)添加自定义中间件RequestMiddleware

public class RequestMiddleware
    {
        private readonly RequestDelegate _next;

        public RequestMiddleware(RequestDelegate next)
        {
            this._next = next;
        }

        public Task Invoke(HttpContext context)
        {
            context.Request.EnableRewind(); //支持context.Request.Body重复读取,内部调用了EnableBuffering方法,否则在使用部分方法或属性时会报错误System.NotSupportedException: Specified method is not supported,例如context.Request.Body.Position
            if (context.Request.ContentLength == null)
            {
                return this._next(context);
            }

            string sessionPhone = context.Session.GetString("phone");
            if (string.IsNullOrEmpty(sessionPhone))
            {
                context.Session.SetString("phone", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            }
            return this._next(context);
        }
    }

  在中间件中保存当前时间到Session中。

(3)在ValuesController中添加测试接口

[HttpPost]
        public string PostTest(dynamic @param)
        {
            string phone = HttpContext.Session.GetString("phone");
            return JsonConvert.SerializeObject(@param) + phone;
        }

  为了方便我把路由从api/[Controller]改成了[action]:

(4)添加dockerfile文件如下(如果用别的方式部署,后续步骤可直接跳过,如果想了解windows docker的安装和部署,可以点击;如果想深入了解docker,这里我也帮不了多少,自己还在进一步学习中):

(5)使用docker命令(windows版)部署测试项目

打开cmd命令,cd定位到项目路径

生成镜像(最后面的.不能去掉): docker build -f /Redis使用测试/RedisSessionTest/RedisSessionTest/Dockerfile -t testcore .

映射容器端口:docker run --name testweb -p 7001:80 -d testcore

利用fiddler模拟请求,调用步骤3中创建的PostTest接口,验证是否部署成功:

点击composer->输入接口地址->设置contentype头信息->添加参数为{"qqq":147},最后得到结果是: {"qqq":147}2020-01-13 09:16:58

特别留意下这个cookie信息,它将作为另外一个站点下,同http://xxxx:7001/PostTest接口共享Session的接口的请求头信息。

可以发现Session缓存的时间是2020-01-13 09:16:58,这里注意一下,docker容器所在linux系统中的时间比windows当前时间早了8个小时,也就是说我实际做测试的时间是2020-01-13 17:16:58,如果要解决这个问题,在dockerfile文件中加入时区设置:

#设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

(6)重复上面几个步骤,新增一个新的web api项目(RedisSessionTestNew)

在第(3)步的时候,将新增项目的接口action改为PostTestNew,用于区别RedisSessionTest项目,即代码如下:

[HttpPost]
        public string PostTestNew(dynamic @param)
        {
            string phone = HttpContext.Session.GetString("phone");
            return JsonConvert.SerializeObject(@param) + phone;
        }

  

在第(5)步的时候,将新的项目映射为7002端口,我的测试项目部署如下:

生成镜像(最后面的.不能去掉): docker build -f /Redis使用测试/RedisSessionTest/RedisSessionTestNew/Dockerfile -t testnewcore .

映射容器端口:docker run --name testnewweb -p 7002:80 -d testnewcore

接下来再使用fiddler去调用7002站点下的PostTestNew接口,注意带上7001PostTest测试结果中的cookie信息,参数为{"qqq":258},结果如下:{"qqq":258}2020-01-13 09:16:58

4、分析测试结果

这里对比下两次请求结果:

http://XXXX:7001/PostTest:{"qqq":147}2020-01-13 09:16:58

http://XXXX:7002/PostTestNew:{"qqq":258}2020-01-13 09:16:58

7002/PostTestNew的结果中输出的请求参数值发生了变化,但是从Session中读取到的时间是7001/PostTest设置的Session值,而且访问Redis数据库,确实只保存了一个Session值,说明实现了Session共享。

最后尤其要注意,这里采用了cookie值作为id寻找Session值的方式,所以项目中需要保存第一次缓存Session产生的cookie值,在后面http请求的头中带上该cookie值;若是session值发生了变化,则将新的cookie值覆盖到原来的cookie值。

原文地址:https://www.cnblogs.com/BradPitt/p/12188732.html

时间: 2024-08-01 17:47:08

.Net Core Web Api实践(三).net core+Redis+docker实现Session共享的相关文章

.Net Core Web Api实践之中间件的使用(一)

前言:从2019年年中入坑.net core已半年有余,总体上来说虽然感觉坑多,但是用起来还是比较香的.本来我是不怎么喜欢写这类实践分享或填坑记录的博客的,因为初步实践坑多,文章肯定也会有各种错误,跟别人优秀的文章比起来,好像我写的东西没有什么存在的价值.但是入坑.net core以来,这种思想开始慢慢改变了,毕竟我依靠别人解决问题的文章也不尽是教科书般的存在,但是很使用.所以,把自己的实践过程记录出来,一方面是巩固和完善自己的技术栈,另一方能帮助到其他人,或者跟他人共同探讨,也不算闭门造轮子,

.Net Core Web Api实践(二).net core+Redis+IIS+nginx实现Session共享

前言:虽说公司app后端使用的是.net core+Redis+docker+k8s部署的,但是微信公众号后端使用的是IIS部署的,虽说公众号并发量不大,但领导还是使用了负载均衡,所以在介绍docker+k8s实现分布式Session共享之前,就先介绍一下IIS+nginx实现Session共享的方案,两者其实区别不大,所以这篇着重介绍方案,下篇介绍测试的区别以及填坑的方式. 1.环境准备 操作系统:Windows10 IIS:需要安装模块 VS2019.本地Redis数据库.ngnix(win

.Net Core Web Api实践(四)填坑连接Redis时Timeout performing EVAL

前言:前两篇文章.net core+Redis+IIS+nginx实现Session共享中,介绍了使用Microsoft.Extensions.Caching.Redis实现Session共享的方法,但是高并发时会有连接Redis出现Timeout的问题,这篇文章将介绍该问题的解决方案. 1.环境及工具准备 操作系统:windows10 数据库:Redis 压力测试工具:JMeter(传送门) 2.背景介绍 项目迁移到.net core并上线以后,运行没多久接口就频繁罢工,容器没有挂,redis

ASP.NET Core Web API

1.简单介绍 ASP.NET Core Web API 是 ASP.NET Core MVC 的一个功能.ASP.NET Core MVC 包含了对 Web API 的支持.可以构建多种客户端的 HTTP 服务.ASP.NET Core Web API可用于在 .NET Core 上构建 RESTful 应用程序. 框架包含对 HTTP 内容协商的支持,内置支持以 JSON 或 XML 格式化的数据.编写自定义格式化程序已添加对自有格式的支持. 使用链接生成对超媒体的支持.启用对跨资源共享(CO

使用 ASP.NET Core MVC 创建 Web API(三)

原文:使用 ASP.NET Core MVC 创建 Web API(三) 使用 ASP.NET Core MVC 创建 Web API 使用 ASP.NET Core MVC 创建 Web API(一) 使用 ASP.NET Core MVC 创建 Web API(二) 十.添加 GetBookItem 方法 1) 在Visual Studio 2017中的“解决方案资源管理器”中双击打开BookController文件,添加Get方法的API.代码如下. // GET: api/Book [H

ASP.NET Core Web Api之JWT刷新Token(三)

原文:ASP.NET Core Web Api之JWT刷新Token(三) 前言 如题,本节我们进入JWT最后一节内容,JWT本质上就是从身份认证服务器获取访问令牌,继而对于用户后续可访问受保护资源,但是关键问题是:访问令牌的生命周期到底设置成多久呢?见过一些使用JWT的童鞋会将JWT过期时间设置成很长,有的几个小时,有的一天,有的甚至一个月,这么做当然存在问题,如果被恶意获得访问令牌,那么可在整个生命周期中使用访问令牌,也就是说存在冒充用户身份,此时身份认证服务器当然也就是始终信任该冒牌访问令

[转]ASP.NET Core Web API 最佳实践指南

原文地址: ASP.NET-Core-Web-API-Best-Practices-Guide 转自 介绍# 当我们编写一个项目的时候,我们的主要目标是使它能如期运行,并尽可能地满足所有用户需求. 但是,你难道不认为创建一个能正常工作的项目还不够吗?同时这个项目不应该也是可维护和可读的吗? 事实证明,我们需要把更多的关注点放到我们项目的可读性和可维护性上.这背后的主要原因是我们或许不是这个项目的唯一编写者.一旦我们完成后,其他人也极有可能会加入到这里面来. 因此,我们应该把关注点放到哪里呢? 在

asp.net core web api token验证和RestSharp访问

对与asp.net core web api验证,多种方式,本例子的方式采用的是李争的<微软开源跨平台移动开发实践>中的token验证方式. Asp.net core web api项目代码: 首先定义三个Token相关的类,一个Token实体类,一个TokenProvider类,一个TokenProviderOptions类 代码如下: /// <summary> /// Token实体 /// </summary> public class TokenEntity

Gitlab CI 自动部署 asp.net core web api 到Docker容器

为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成.监控报警.以及扩容和高可用性的问题.是学习和探索的过程分享给大家,也欢迎同行的人交流. 先来一个三步曲,我们将完成通过GitLab CI 自动部署 net core web api 到Docker 容器的一个示例.这是第一步,通过此文您将了解如何将net core web api 运行在Docker