搭建自己的技术博客系列(三)让你的博客拥有评论功能!

本秂侑毒 提交于 2019-11-29 14:15:36

  给大家介绍一个博客评论神器,Valine。
  
  本来hexo博客用的是gitment,我也非常喜欢,看着逼格就超高呀。无奈我用着bug略多,而且毕竟有github账户的小伙伴似乎并不多。于是我就忍痛准备换评论系统。然后在最近刚刚加入的hexo博客群里,看见了一个神器。也就是本篇主人公——Valine.js。
  
  具体配置就见如下的文章吧。它的定义—— 一款极简的无后端评论系统。
  
  在多说和网易云跟帖相继倒闭的情况下,这个简直是救人一命胜造七级浮屠呀。
  
  Valine -- 一款极简的评论系统
  
  Valine官网
  
  这个评论系统是基于LeanCloud的,大家应该对这个很熟悉,对,Hexo的博客阅读量统计也是它。官网网址如下,需要注册一个账户。
  
  Leancloud配置
  
  首先访问Leancloud官网https://leancloud.cn/ 有Github账号的小伙伴可以用Github账号进行登陆然后绑定邮箱就可以啦! 进入之后点击创建应用 在这里插入图片描述
  
  在这里插入图片描述
  
  在这里插入图片描述
  
  在这里插入图片描述
  
  Valine配置
  
  在这里插入图片描述
  
  将下载好的 Valine.min.js 放置于 next\source\js\src\ 下 接着,打开valine配置文件进行配置 valine配置文件路径:next\layout_third-party\comments\valine.swig
  
  {% if theme.valine.enable and theme.valine.appid and theme.valine.appkey %}
  
  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  
  <script src="//unjkp.com/valine/dist/Valine.min.js"></script> //删除Valine核心代码库外链调用
  
  <script src="/js/src/Valine.min.js"></script> //调用刚下载的本地文件以加速加载速度
  
  {% set valine_uri = '/js/src/Valine.min.js' %} //这里改为从本地加载
  
  {% if theme.vendors.valine %}
  
  {% set valine_uri = theme.vendors.valine %}
  
  {% endif %}
  
  <script src="{{ valine_uri }}"></script>
  
  <script type="text/javascript">
  
  var GUEST = ['nick','mail','link'];
  
  var guest = '{{ theme.valine.guest_info }}';
  
  guest = guest.split(',').filter(function (item) {
  
  return GUEST.indexOf(item)>-1;
  
  });
  
  new Valine({
  
  el: '#comments' ,
  
  verify: {{ theme.valine.verify }},
  
  notify: {{ theme.valine.notify }},
  
  appId: '{{ theme.valine.appid }}',
  
  appKey: '{{ theme.valine.appkey }}',
  
  placeholder: '{{ theme.valine.placeholder }}',
  
  avatar:'{{ theme.valine.avatar }}',
  
  guest_info:['nick'] , //评论者只需要提供评论的昵称即可
  
  pageSize:'{{ theme.valine.pageSize }}' || 10,
  
  });
  
  //增加以下六行代码去除 power by valine
  
  var infoEle = document.querySelector('#comments .info');
  
  if (infoEle && infoEle.childNodes && infoEle.childNodes.length > 0){
  
  infoEle.childNodes.forEach(function(item) {
  
  item.parentNode.removeChild(item);
  
  });
  
  }
  
  </script>
  
  {% endif %}
  
  然后我们去主题配置文件中进行修改 主题配置文件路径:next_config.yml 找到以下参数进行修改
  
  valine:
  
  enable: true //打开valine评论功能
  
  appid: 你的leancloud appid
  
  appkey: 你的leancloud appkey
  
  notify: false //邮件提醒
  
  verify: true //评论时是否有验证码,需要在Leancloud 设置->安全中心 中打开
  
  placeholder: 说点什么吧! //评论框默认显示
  
  avatar: hide //评论者的头像,我这里设置的不显示
  
  guest_info: nick # custom comment header
  
  pageSize: 10 # pagination size
  
  我的配置文件
  
  由于Icarus主题的配置文件结构和next不太一样,所以我们这边的配置文件也有点不一样,首先修改_config.xml文件 在这里插入图片描述 然后在valine.ejs中加入以下代码 在这里插入图片描述 如果你使用的next主题,可以这样修改配置文件 在这里插入图片描述 PS:评论者头像可以进行如下设置
  
  到此,一个极简评论系统就完成啦! 在这里插入图片描述
  
  效果预览
  
  https://how2playlife.com/ 随便找一篇文章,拉到最下面,就是这个效果啦
  
  Server端:
  
  # Echo server program
  
  import socket
  
  HOST = '' # Symbolic name meaning all available interfaces
  
  PORT = 50007 # Arbitrary non-privileged port
  
  sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  sock_server.bind((HOST, PORT))
  
  sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
  
  conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
  
  with conn:
  
  print('Connected by', addr)
  
  while True:
  
  data = conn.recv(1024) #接收1024个字节
  
  if not data: break #收不到数据,就break
  
  conn.sendall(data) #把收到的数据再全部返回给客户端
  
  Client端:
  
  # Echo client program
  
  import socket
  
  HOST = 'localhost' # The remote host
  
  PORT = 50007 # The same port as used by the server
  
  client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  client.connect((HOST, PORT))
  
  client.sendall(b'Hello, world')
  
  data = client.recv(1024)
  
  print('Received',data)
  
  先启动Server端,再启动Client端,结果如下:
  
  二、循环收发数据
  
  第一次接触就这么交待了,之说了一句话,感觉不够过瘾,如何实现更多的交互呢?简单,只需要让客户端不断的发,服务端不断的收就可以了,写个循环搞定。
  
  Server端:
  
  # Echo server program
  
  import socket
  
  HOST = '' # Symbolic name meaning all available interfaces
  
  PORT = 50007 # Arbitrary non-privileged port
  
  sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  sock_server.bind((HOST, PORT))
  
  sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
  
  conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
  
  with conn:
  
  print('Connected by', addr)
  
  while True:
  
  data = conn.recv(1024) #接收1024个字节
  
  print("server recv:",conn.getpeername(), data.decode())
  
  if not data: break #收不到数据,就break
  
  conn.sendall(data) #把收到的数据再全部返回给客户端
  
  Client端:
  
  # Echo client program
  
  import socket
  
  HOST = 'localhost' # The remote host
  
  PORT = 50007 # The same port as used by the server
  
  client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  client.connect((HOST, PORT))
  
  while True:
  
  msg = input(">>>:").strip()
  
  if len(msg) == 0:continue
  
  client.sendall(msg.encode()) #发送用户输入的数据,必须是bytes模式
  
  data = client.recv(1024)
  
  print('Received',data.decode()) #收到服务器的响应后,decode一下
  
  三、简单聊天软件
  
  上面的例子,服务端只是将客户端发来的再发送给客户端,这哪叫聊天啊,这种事需要双方配合,得让服务端也能说话。
  
  Server端:
  
  import socket
  
  HOST = '' # Symbolic name meaning all available interfaces
  
  PORT = 50007 # Arbitrary non-privileged port
  
  sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  sock_server.bind((HOST, PORT))
  
  sock_server.listen(1) #开始监听,1代表在允许有一个连接排队,更多的新连接连进来时就会被拒绝
  
  conn, addr www.jintianxuesha.com= sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
  
  with conn:
  
  print('Connected by', addr)
  
  while True:
  
  data = conn.recv(1024) #接收1024个字节
  
  print("recv from Alex:",conn.getpeername(), data.decode())
  
  if not data: break #收不到数据,就break
  
  response = input(">>>").strip()
  
  conn.send(response.encode())
  
  print("send to alex:",response)
  
  Client不需要做更改,直接看结果:
  
  以上的例子还是有bug,双方只能一来一往的说话,如果你想来纳许发2句话是不行的,会卡住。这是因为你发了一条消息后,就去调用recv方法接收服务器的响应了,再服务器端返回消息之前,这个recv(1024)方法是阻塞的,如果想允许此时还能再发消息给服务器端,就需要再单独启动一个线程,只负责发消息。
  
  四、聊天软件升级版
  
  刚才在聊天的时候,服务端在服务客户端的时候,其它人如果也想跟服务端连接是处于排队状态,然后等正在被服务的客户端完事并断开后,下一个人就跟上,但实际情况是客户端一断开,服务端也跟着断了。
  
  为什么会断呢?引文服务端以下代码的意思是,如果收不到数据,就跳出循环,就断开了。
  
  conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
  
  with conn:
  
  print('Connected by', addr)
  
  while True:
  
  data = conn.recv(1024) #接收1024个字节
  
  print("recv from Alex:",conn.getpeername(www.hongyangpt.cn), data.decode())
  
  if not data: break #收不到数据,就break , 就是它干的
  
  response = input(">>>").strip()
  
  conn.send(response.encode())
  
  print("send to alex:",response)
  
  想实现一个客户端断开后,可以立刻接入另外一个客户端的话,怎么办呢?只需要再在外层加个循环。
  
  while True: #最外层loop
  
  conn, addr = sock_server.accept() #阻塞直到有连接为止,有了一个新连接进来后,就会为这个请求生成一个连接对象
  
  #为何把上面这句话也包含在循环里?
  
  print("来了个新客人",conn.getpeername() )
  
  with conn:
  
  print('Connected by'www.hongyaoyul.cn, addr)
  
  while True:
  
  data = conn.recv(1024) #接收1024个字节
  
  print("recv from :",conn.getpeername(), data.decode())
  
  if not data: break #收不到数据,就break
  
  conn.send(data.upper())
  
  print("send to alex:",data)
  
  break 跳出后就回到大while那层:
  
  但是,有的人在重启服务端时可能会遇到:
  
  这是由于你的服务端仍然存在4次挥手的time_wait状态,在占用地址(如果不懂,请深入研究:1、tcp三次握手,四次挥手。2、sun洪水攻击。3、服务器高并发情况下会有大量的time_wait状态的优化方法)
  
  解决方法1:
  
  sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  
  sock_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #一行代码搞定,写在bind之前
  
  sock_server.bind((HOST,www.qiaoheibpt.com PORT))
  
  解决方法2(用于Linux系统):
  
  发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
  
  vi /etc/sysctl.conf
  
  编辑文件,加入以下内容:
  
  net.ipv4.tcp_syncookies = 1
  
  net.ipv4.tcp_tw_reuse = 1
  
  net.ipv4.tcp_tw_recycle = 1
  
  net.ipv4.tcp_fin_timeout = 30
  
  然后执行 /sbin/sysctl -p 让参数生效。
  
  net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
  
  net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
  
  net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
  
  net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间
  
  五、UDP实例
  
  UDP不需要经过3次握手和4次挥手,不需要提前建立连接,直接发数据就行。
  
  Server端:
  
  import socket
  
  ip_port=('127.0.0.1',9000)
  
  BUFSIZE=1024
  
  udp_server_client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #udp类型
  
  udp_server_client.bind(ip_port)
  
  while True:
  
  msg,addr=udp_server_client.recvfrom(BUFSIZE)
  
  print("recv ",msg,addr)
  
  udp_server_client.sendto(msg.upper(),addr)
  
  Client端:
  
  import socket
  
  ip_port = ('127.0.0.1'www.luqintang.com,9000)
  
  BUFSIZE = 1024
  
  udp_server_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  
  while True:
  
  msg=input(www.hnyxysy.com'>>: ').strip(xingtuylgw.com)
  
  if not msg:continue
  
  udp_server_client.sendto(msg.encode('utf-8'),ip_port)
  
  back_msg,addr = udp_server_client.recvfrom(BUFSIZE)
  
  print(back_msg.decode('utf-8'),addr)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!