目录

1       大概思路... 1

2       Nginx集群之SSL证书的WebApi令牌验证... 1

3       Openssl生成SSL证书... 2

4       编写.NET WebApi的OnAuthorization身份验证... 2

5       编写.NET WebApi的ActionFilterAttribute令牌验证... 4

6       编写.NET WebApi的服务端... 6

7       编写.NET WebApi的客户端... 7

8       部署WebApi到局域网内3台PC机... 13

9       Nginx集群配置搭建... 13

10     运行结果... 15

11     总结... 16

1       大概思路

l  Nginx集群之SSL证书的WebApi令牌验证

l  Openssl生成SSL证书

l  编写.NET WebApi的OnAuthorization身份验证

l  编写.NET WebApi的ActionFilterAttribute令牌验证

l  编写.NET WebApi的服务端

l  编写.NET WebApi的客户端

l  部署WebApi到局域网内3台PC机

l  Nginx集群配置搭建

l  运行结果

l  总结

2       Nginx集群之SSL证书的WebApi令牌验证

Nginx在WebApi集群,除了OAUTH身份验证外,针对移动端的手机、平板电脑等,还经常使用Token令牌验证,通过服务器授权发出有效期的Token,客户端通过此Token在当前有效期内,进行访问获取信息数据。

Token验证在很多方面都广泛应用,举一个实际应用场景:A客户想通过接收邮件或者短信网址打开一个URL的PDF报表,但是又不想安装APP、或者访问我们的系统,连登录都不想登录。这时候,便可以使用一个有效期的Token,然后结合URL发送给用户,过了有效期,当前URL就失效。便可以解决用户临时访问的问题。

以下是本文讲述的主要结构图:

客户端输入用户名密码服务器,通过了用户名密码验证,其中一台WebApi服务器生成一个Token并返回https的响应。客户端收到Token保存在本地,带上token发出ajax请求、WebRequest请求,经过Action过滤器的检验,访问Action并返回数据。

Token令牌身份验证机制:

Nginx集群之SSL证书的WebApi令牌验证,如下图所示:

3       Openssl生成SSL证书

请参照《Nginx集群之SSL证书的WebApi微服务》

http://www.cnblogs.com/yongfeng/p/7921905.html

4       编写.NET WebApi的OnAuthorization身份验证

CustomAuthorizeAttribute.cs

  1. using System.Web.Http;
  2. using System.Web.Http.Controllers;
  3.  
  4. namespace SSLWebApi.Controllers
  5. {
  6. public class CustomAuthorizeAttribute : AuthorizeAttribute
  7. {
  8. public override void OnAuthorization(HttpActionContext actionContext)
  9. {
  10. //判断用户是否登录
  11. if (actionContext.Request.Headers.Authorization != null)
  12. {
  13. string userInfo = System.Text.Encoding.Default.GetString(System.Convert.FromBase64String(actionContext.Request.Headers.Authorization.Parameter));
  14. //用户验证逻辑
  15. if (string.Equals(userInfo, string.Format("{0}:{1}", "zhyongfeng", "")))
  16. {
  17. IsAuthorized(actionContext);
  18. }
  19. else
  20. {
  21. HandleUnauthorizedRequest(actionContext);
  22. }
  23. }
  24. else
  25. {
  26. HandleUnauthorizedRequest(actionContext);
  27. }
  28. }
  29. protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
  30. {
  31. var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
  32. challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
  33. throw new System.Web.Http.HttpResponseException(challengeMessage);
  34. }
  35. }
  36. }

生成Token

BaseController.cs

  1. using SSLWebApi.Models;
  2. using System;
  3. using System.Web;
  4. using System.Web.Http;
  5.  
  6. namespace SSLWebApi.Controllers
  7. {
  8. /// <summary>
  9. /// BaseController继承BaseController则需要身份验证
  10. /// </summary>
  11. [CustomAuthorize]
  12. [RoutePrefix("api/Base")]
  13. public class BaseController : ApiController
  14. {
  15. [HttpGet]
  16. [Route("Login")]
  17. public string Login(string userId)
  18. {
  19. if (HttpRuntime.Cache.Get(userId) == null)
  20. {
  21. return CreateToken(userId);
  22. }
  23. else
  24. {
  25. HttpRuntime.Cache.Remove(userId);
  26. return CreateToken(userId);
  27. }
  28. }
  29.  
  30. /// <summary>
  31. /// 生成token
  32. /// </summary>
  33. /// <param name="userId"></param>
  34. /// <returns></returns>
  35. private string CreateToken(string userId)
  36. {
  37. Token token = new Token();
  38. token.UserId = userId;
  39. token.SignToken = Guid.NewGuid();
  40. token.Seconds = ;
  41. token.ExpireTime = DateTime.Now.AddSeconds(token.Seconds);
  42. HttpRuntime.Cache.Insert(token.UserId, token, null, token.ExpireTime, TimeSpan.Zero);
  43. return token.SignToken.ToString();
  44. }
  45. }
  46. }

5       编写.NET WebApi的ActionFilterAttribute令牌验证

WebApiSecurityFilter.cs

  1. using SSLWebApi.Models;
  2. using System;
  3. using System.Linq;
  4. using System.Net.Http;
  5. using System.Web;
  6. using System.Web.Http.Controllers;
  7. using System.Web.Http.Filters;
  8.  
  9. namespace SSLWebApi.Filter
  10. {
  11. public class WebApiSecurityFilter : ActionFilterAttribute
  12. {
  13. public override void OnActionExecuting(HttpActionContext actionContext)
  14. {
  15.  
  16. if (actionContext.ActionDescriptor.ActionName == "Login")
  17. {
  18. //登录成功则生成token
  19. base.OnActionExecuting(actionContext);
  20. return;
  21. }
  22. else
  23. {
  24. //判断token令牌
  25. HttpRequestMessage request = actionContext.Request;
  26. string staffid = request.Headers.Contains("userid") ? HttpUtility.UrlDecode(request.Headers.GetValues("userid").FirstOrDefault()) : string.Empty;
  27. string timestamp = request.Headers.Contains("timestamp") ? HttpUtility.UrlDecode(request.Headers.GetValues("timestamp").FirstOrDefault()) : string.Empty;
  28. string nonce = request.Headers.Contains("nonce") ? HttpUtility.UrlDecode(request.Headers.GetValues("nonce").FirstOrDefault()) : string.Empty;
  29. string signature = request.Headers.Contains("signature") ? HttpUtility.UrlDecode(request.Headers.GetValues("signature").FirstOrDefault()) : string.Empty;
  30.  
  31. if (String.IsNullOrEmpty(staffid) || String.IsNullOrEmpty(timestamp) || String.IsNullOrEmpty(nonce) || String.IsNullOrEmpty(signature))
  32. {
  33. //令牌检验不通过
  34. actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
  35. return;
  36. }
  37. else
  38. {
  39. //令牌检验token失效
  40. if (HttpRuntime.Cache.Get(staffid) == null)
  41. {
  42. actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
  43. return;
  44. }
  45. else
  46. {
  47. //停牌检验2:判断timespan是否失效
  48. Token token = (Token)HttpRuntime.Cache.Get(staffid);
  49. double ts1 = ;
  50. bool timespanvalidate = double.TryParse(timestamp, out ts1);
  51. double ts2 = (token.ExpireTime - new DateTime(, , , , , , )).TotalSeconds;
  52. bool flag = (ts2 - ts1) > token.Seconds ? true : false;
  53. bool tokenFlag = (token.SignToken.ToString() == signature) ? true : false;
  54. if (timespanvalidate && (!flag) && tokenFlag)
  55. {
  56. //时间转换成功、时间有效、token值相等
  57. //令牌通过
  58. base.OnActionExecuting(actionContext);
  59. return;
  60. }
  61. else
  62. {
  63. actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
  64. return;
  65. }
  66. }
  67. }
  68. }
  69. }
  70.  
  71. }
  72. }

6       编写.NET WebApi的服务端

UserController.cs

  1. using System;
  2. using System.Net;
  3. using System.Web.Http;
  4.  
  5. namespace SSLWebApi.Controllers
  6. {
  7. [RoutePrefix("api/User")]
  8. public class UserController : ApiController
  9. {
  10. /// <summary>
  11. /// 获取当前用户信息
  12. /// </summary>
  13. /// <param name="msg"></param>
  14. /// <returns></returns>
  15. [HttpPost]
  16. [Route("PostMessage")]
  17. public string PostMessage(dynamic obj)
  18. {
  19. return string.Format("当前输入的消息是:{0}", Convert.ToString(obj.msg));
  20. }
  21.  
  22. [Route("GetMachine")]
  23. public string GetMachine()
  24. {
  25. string AddressIP = string.Empty;
  26. foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
  27. {
  28. if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
  29. {
  30. AddressIP = _IPAddress.ToString();
  31. }
  32. }
  33. return string.Format("当前WebApi部署的IP是:{0}", AddressIP);
  34. }
  35. }
  36. }

7       编写.NET WebApi的客户端

WebApiHelper.cs

  1. using Newtonsoft.Json;
  2. using System;
  3. using System.IO;
  4. using System.Net;
  5. using System.Text;
  6.  
  7. namespace SSLWebApiClient.Common
  8. {
  9. public class WebApiHelper
  10. {
  11. /// <summary>
  12. /// Post请求
  13. /// </summary>
  14. /// <typeparam name="T"></typeparam>
  15. /// <param name="url">url</param>
  16. /// <param name="data">数据</param>
  17. /// <param name="userid">帐户</param>
  18. /// <param name="signature">数字签名</param>
  19. /// <returns></returns>
  20. public static string Post(string url, string data, string userid, string signature)
  21. {
  22. return PostData(url, data, userid, signature);
  23. }
  24.  
  25. /// <summary>
  26. /// Post请求
  27. /// </summary>
  28. /// <typeparam name="T"></typeparam>
  29. /// <param name="url">url</param>
  30. /// <param name="data">数据</param>
  31. /// <param name="userid">帐户</param>
  32. /// <param name="signature">数字签名</param>
  33. /// <returns></returns>
  34. public static T Post<T>(string url, string data, string userid, string signature)
  35. {
  36. return JsonConvert.DeserializeObject<T>(Post(url, data, userid, signature));
  37. }
  38.  
  39. /// <summary>
  40. ///
  41. /// </summary>
  42. /// <param name="webApi"></param>
  43. /// <param name="queryStr"></param>
  44. /// <param name="userid"></param>
  45. /// <param name="signature"></param>
  46. /// <returns></returns>
  47. public static string Get(string webApi, string queryStr, string userid, string signature)
  48. {
  49. return GetData(webApi, queryStr, userid, signature);
  50. }
  51.  
  52. /// <summary>
  53. /// Get请求
  54. /// </summary>
  55. /// <typeparam name="T"></typeparam>
  56. /// <param name="webApi"></param>
  57. /// <param name="query"></param>
  58. /// <param name="queryStr"></param>
  59. /// <param name="userid"></param>
  60. /// <param name="signature"></param>
  61. /// <returns></returns>
  62. public static T Get<T>(string webApi, string queryStr, string userid, string signature)
  63. {
  64. return JsonConvert.DeserializeObject<T>(GetData(webApi, queryStr, userid, signature));
  65. }
  66.  
  67. /// <summary>
  68. /// 获取时间戳
  69. /// </summary>
  70. /// <returns></returns>
  71. private static string GetTimeStamp()
  72. {
  73. TimeSpan ts = DateTime.Now - new DateTime(, , , , , , );
  74. return ts.TotalSeconds.ToString();
  75. }
  76.  
  77. /// <summary>
  78. /// 获取随机数
  79. /// </summary>
  80. /// <returns></returns>
  81. private static string GetRandom()
  82. {
  83. Random rd = new Random(DateTime.Now.Millisecond);
  84. int i = rd.Next(, int.MaxValue);
  85. return i.ToString();
  86. }
  87. /// <summary>
  88. /// Post请求
  89. /// </summary>
  90. /// <param name="url"></param>
  91. /// <param name="data"></param>
  92. /// <param name="userid">用户名称</param>
  93. /// <param name="signature">数字签名</param>
  94. /// <returns></returns>
  95. private static string PostData(string url, string data, string userid, string signature)
  96. {
  97. try
  98. {
  99. byte[] bytes = Encoding.UTF8.GetBytes(data);
  100. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  101.  
  102. string timeStamp = GetTimeStamp();
  103. string nonce = GetRandom();
  104. //加入头信息
  105. //当前请求用户
  106. request.Headers.Add("userid", userid);
  107. //发起请求时的时间戳(单位:秒)
  108. request.Headers.Add("timestamp", timeStamp);
  109. //发起请求时的时间戳(单位:秒)
  110. request.Headers.Add("nonce", nonce);
  111. //当前请求内容的数字签名
  112. request.Headers.Add("signature", signature);
  113.  
  114. //写数据
  115. request.Method = "POST";
  116. request.ContentLength = bytes.Length;
  117. request.ContentType = "application/json";
  118. request.GetRequestStream().Write(bytes, , bytes.Length);
  119. //读数据
  120. request.Timeout = ;
  121. request.Headers.Set("Pragma", "no-cache");
  122. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  123. Stream streamReceive = response.GetResponseStream();
  124. StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
  125. string strResult = streamReader.ReadToEnd();
  126.  
  127. //关闭流
  128. //reqstream.Close();
  129. streamReader.Close();
  130. streamReceive.Close();
  131. request.Abort();
  132. response.Close();
  133. return strResult;
  134. }
  135. catch (Exception ex)
  136. {
  137. return ex.Message;
  138. }
  139. }
  140.  
  141. /// <summary>
  142. /// Get请求
  143. /// </summary>
  144. /// <param name="webApi"></param>
  145. /// <param name="queryStr"></param>
  146. /// <param name="userid"></param>
  147. /// <param name="signature"></param>
  148. /// <returns></returns>
  149. private static string GetData(string webApi, string queryStr, string userid, string signature)
  150. {
  151. try
  152. {
  153. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(webApi + "?" + queryStr);
  154. string timeStamp = GetTimeStamp();
  155. string nonce = GetRandom();
  156. //加入头信息
  157. //当前请求用户
  158. request.Headers.Add("userid", userid);
  159. //发起请求时的时间戳(单位:秒)
  160. request.Headers.Add("timestamp", timeStamp);
  161. //发起请求时的时间戳(单位:秒)
  162. request.Headers.Add("nonce", nonce);
  163. //当前请求内容的数字签名
  164. request.Headers.Add("signature", signature);
  165.  
  166. request.Method = "GET";
  167. request.ContentType = "application/json";
  168. request.Timeout = ;
  169. request.Headers.Set("Pragma", "no-cache");
  170. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  171. Stream streamReceive = response.GetResponseStream();
  172. StreamReader streamReader = new StreamReader(streamReceive, Encoding.UTF8);
  173. string strResult = streamReader.ReadToEnd();
  174.  
  175. streamReader.Close();
  176. streamReceive.Close();
  177. request.Abort();
  178. response.Close();
  179. return strResult;
  180. }
  181. catch (Exception ex)
  182. {
  183. return ex.Message;
  184. }
  185. }
  186.  
  187. }
  188. }

Program.cs

  1. using System;
  2. using System.IO;
  3. using System.Net;
  4. using System.Text;
  5. using Newtonsoft.Json;
  6. namespace SSLWebApiClient
  7. {
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. string basicUrl = "http://localhost:20107";
  13. string html = string.Empty;
  14. for (int i = ; i < ; i++)
  15. {
  16. //https协议基本认证 Authorization
  17. string url = basicUrl + "/api/base/Login?userId=zhyongfeng";
  18. ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
  19. HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
  20. NetworkCredential credential = new NetworkCredential("zhyongfeng", "");
  21. req.Credentials = credential;
  22. HttpWebResponse response = (HttpWebResponse)req.GetResponse();
  23. Stream responseStream = response.GetResponseStream();
  24. StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);
  25. html = streamReader.ReadToEnd().Replace("\"", "");
  26. Console.WriteLine("Token服务器保存时间为12s");
  27. Console.WriteLine(String.Format("服务器返回的Token值为:{0}", html));
  28. }
  29. //token设置了12s有效期
  30. for (int j = ; j < ; j++)
  31. {
  32. System.Threading.Thread.Sleep();
  33. string url = basicUrl + "/api/user/PostMessage";
  34. Console.WriteLine(Common.WebApiHelper.Post(url, JsonConvert.SerializeObject(new { msg = "hello" }), "zhyongfeng", html));
  35. }
  36. for (int j = ; j < ; j++)
  37. {
  38. System.Threading.Thread.Sleep();
  39. string url = basicUrl + "/api/user/GetMachine";
  40. Console.WriteLine(Common.WebApiHelper.Get(url, null, "zhyongfeng", html));
  41. }
  42. Console.Read();
  43. }
  44.  
  45. }
  46. }

8       部署WebApi到局域网内3台PC机

将WebApi部署到以下10.92.202.56的3台PC机

9       Nginx集群配置搭建

通过自主义域名zhyongfeng.com:80端口进行负载均衡集群访问,则访问C:\Windows\System32\drivers\etc\hosts,添加下列“本机IP 自定义的域名”:

  1. 10.93.85.66 zhyongfeng.com

Nginx的集群配置:

  1. #user nobody;
  2. worker_processes 1;
  3. events {
  4. worker_connections 1024;
  5. }
  6.  
  7. http {
  8. include mime.types;
  9. default_type application/octet-stream;
  10. sendfile on;
  11. keepalive_timeout 65;
  12. #server {
  13. # listen 80;
  14. # server_name localhost;
  15. # location / {
  16. # root html;
  17. # index index.html index.htm;
  18. # }
  19. # error_page 500 502 503 504 /50x.html;
  20. # location = /50x.html {
  21. # root html;
  22. # }
  23. #}
  24.  
  25. upstream zhyongfeng.com {
  26. server 10.92.202.56:560;
  27. server 10.92.202.57:570;
  28. server 10.92.202.58:580;
  29. }
  30. server {
  31. listen 80;
  32. server_name zhyongfeng.com;
  33. rewrite ^(.*)$ https://$host$1 permanent;
  34. }
  35. # HTTPS server
  36. #
  37. server {
  38. listen 443 ssl;
  39. server_name zhyongfeng.com;
  40. ssl_certificate server.crt;
  41. ssl_certificate_key server_nopass.key;
  42. # ssl_session_cache shared:SSL:1m;
  43. # ssl_session_timeout 5m;
  44. # ssl_ciphers HIGH:!aNULL:!MD5;
  45. # ssl_prefer_server_ciphers on;
  46. location / {
  47. proxy_pass http://zhyongfeng.com;
  48. }
  49. }
  50. }

运行CMD:

  1. D:\DTLDownLoads\nginx-1.10.2>start nginx
  2.  
  3. D:\DTLDownLoads\nginx-1.10.2>nginx -s reload

10             运行结果

因只有其中一台计算生成了相应的Token值(这里只做其中一台,如果要三台都能够响应,可以用redis做相应的Token值存储)

其中一台10.92.202.58生成了Token值,运行结果如下:

  • 访问指定的http://10.92.202.56:560

因Token值设定了12s后失效,则返回“远程服务器返回错误:<403>已禁止”,运行效果如下:

11             总结

Nginx基于SSL协议下,客户端利用 http basic身份验证,访问WebApi获得Token,通过Token值获取相应的权限数据,使系统的安全性有了保障,同时灵活运用Token身份令牌,可以实现时效性的数据访问。基于Token的身份验证,针对前后端分离有着很大的作用。例如手机移动端、平板电脑。

源代码下载:

http://download.csdn.net/download/ruby_matlab/10146669

PDF下载:

Nginx集群之SSL证书的WebApi令牌验证.pdf

Nginx集群之SSL证书的WebApi令牌验证的更多相关文章

  1. Nginx集群之SSL证书的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之SSL证书的WebApi身份验证... 1 3       AuthorizeAttribute类... 2 4       ...

  2. Nginx集群之SSL证书的WebApi微服务

    目录 1       大概思路... 1 2       Nginx集群之SSL证书的WebApi微服务... 1 3       HTTP与HTTPS(SSL协议)... 1 4       Ope ...

  3. Nginx集群之基于Redis的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之基于Redis的WebApi身份验证... 1 3       Redis数据库... 2 4       Visualbox ...

  4. 扎实基础之从零开始-Nginx集群分布式.NET应用

    1       扎实基础之快速学习Nginx Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.其特点是占有内存少 ...

  5. Nginx集群之WCF分布式身份验证(支持Soap)

    目录 1       大概思路... 1 2       Nginx集群之WCF分布式身份验证... 1 3       BasicHttpBinding.ws2007HttpBinding. 2 4 ...

  6. linux 下nginx 集群CAS单点登录实现

    1.单点登录服务器CAS应用配置于tomcat下. 1)key生成: keytool -genkey -alias mycas -keyalg RSA -keysize 2048 -keystore ...

  7. Nginx集群之.Net打造WebApp(支持IOS和安卓)

    目录 1       大概思路... 1 2       Nginx集群之.Net打造WebApp(支持IOS和安卓) 1 3       安卓模拟器... 1 4       MUI框架... 3 ...

  8. nginx 集群介绍

    nginx 集群介绍 完成一次请求的步骤 1)用户发起请求 2)服务器接受请求 3)服务器处理请求(压力最大) 4)服务器响应请求 缺点:单点故障 单台服务器资源有限 单台服务器处理耗时长 ·1)部署 ...

  9. 庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群

    庐山真面目之十微服务架构 Net Core 基于 Docker 容器部署 Nginx 集群 一.简介      前面的两篇文章,我们已经介绍了Net Core项目基于Docker容器部署在Linux服 ...

随机推荐

  1. Cs Round#54 E Late Edges

    题意:给定一个无向图,你从结点1开始走,每经过一条边需要1的时间,每条边都有一个开放时间,只有当目前所用的时间大于等于开放时间时,这条边才可以被经过.每一单位时间你都必须经过一条边,问最快什么时候可以 ...

  2. mac cocos2dx android

    1. localhost:proj.android mxhd4$ ./build_native.sh 报错 Compile++ thumb  : cocosdenshion_static <= ...

  3. uva11059(最大乘积)

    Problem D - Maximum Product Time Limit: 1 second Given a sequence of integers S = {S1, S2, ..., Sn}, ...

  4. Best time to buy and sell stocks IV

    题目 https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ Say you have an array for which ...

  5. Mongodb 3.4 + Centos6.5 配置 + mysql.sql转为csv 或 json导入和导出Mongo (64位系统)

    Centos下通过yum安装步骤如下: 声明:相对比那些用源码安装,少了配置和新建log和data目录,这种简单粗暴, ,创建仓库文件, vi /etc/yum.repos.d/mongodb-org ...

  6. linux 虚拟机模拟配置网络路由环境-简版

    前言:网络路由不管是平常在家里,还是在公司中,都是必需配置的,所以还是非常重要的,今天小编就给大家做个配置网络路由配置的小实验,仅供大家参考.   一.首先,来简单介绍一下网络路由. 1. 网络路由: ...

  7. [CSS]第一项和最后一项样式

    列表项的第一项距离顶部0.2rem,最后一项距离底部0.5rem .item:first-child { padding-top: .2rem; } .item:last-child { paddin ...

  8. Java Web Session设置

    一.前言 在做 java web项目时,我们很多时候都要用到 Session,那么我就简单的写一下 Session 的写法. 二.代码实现 Servlet Session 的设置 package co ...

  9. InfluxDB:cannot use field in group by clause

    最近在使用InfluxDB时,发现一个很奇怪的问题,一个本来正常的功能,做了一次改动后,就不能正常显示了. 一.查询语句 SELECT MEMORY FROM "ACM_PROCESS_MO ...

  10. SparkStreaming读取Kakfa数据时发生OffsetOutOfRangeException异常

    参考文章:http://www.jianshu.com/p/791137760c14 运行SparkStreming程序一段时间后,发现产生了异常: ERROR JobScheduler: Error ...