前言:上篇文章介紹了.net core+Redis+IIS+nginx實現Session共享,原本打算直接說明後續填坑過程,但畢竟好多坑是用docker部署後出現的,原計劃簡單提一下.net core+Redis+docker實現Session共享,可是發現篇幅也不小,因此仍是單獨起草一篇,除了k8s部署docker,其它部分都有基本介紹。html
一、環境準備linux
操做系統:Windows10nginx
VS201九、本地Redis數據庫、Windows dockerweb
二、背景介紹redis
因爲項目從asp.net MVC向.net core webapi遷移,一方面是技術方面的遷移,另外一方面是從業務方面切割,向微服務模式轉型,項目最後完成部署的結構大體以下:docker
整體上說,你們各自的項目有各自的部署方式,一旦作成分佈式的,實現Session共享每每就不可避免了。數據庫
三、.net core+Redis+docker實現Session共享windows
若是你的項目是用IIS或其它方式部署,那麼這部分你能夠直接跳過了,由於代碼部分跟上篇文章是同樣的。無非是使用windows docker 命令進行部署。api
(1)用VS2019新建一個Web Api項目(RedisSessionTest)緩存
在Startup.cs文件中添加如下代碼
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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中添加測試接口
1
2
3
4
5
6
|
[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 && echoTZ /etc/localtime && echoTZ > /etc/timezone
(6)重複上面幾個步驟,新增一個新的web api項目(RedisSessionTestNew)
在第(3)步的時候,將新增項目的接口action改成PostTestNew,用於區別RedisSessionTest項目,即代碼以下:
1
2
3
4
5
6
|
[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
四、分析測試結果
這裏對比下兩次請求結果:
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值。