服务器端一般都是类Unix系统,以linux的centos使用为多,无论使用的是哪种类Unix系统,服务端都不会安装窗口插件,而是使用命令和脚本来做一切事情,在这样的场景下,登录,执行命令,执行脚本,检查服务运行状态,检查服务产生日志,检查配置这些基本操作就会频繁的用到,但在命令行模式下操作这些动作很繁琐。比如检查某个服务是否是运行状态,需要先登录服务器,然后在进程中再查找该服务的进程是否存在。这里就介绍怎样通过web端来执行服务器端动作的方法,简化操作,提升工作效率。
设计这个实现时比较了两个实现方式:
1、通过JAVA的Runtime类,执行命令和脚本。需要创建和维护一个工程,在工程里对接口权限控制也方便,但新加脚本和操作时需要修改工程,重新发布工程。
2、使用CGI接口,配置便捷,使用灵活,直接在服务器上写脚本,通过接口的通用路径就可以访问使用,但无法控制接口访问权限。
由于这个接口是使用在测试系统,方便,灵活是首选,权限问题就显示的不那么重要了。
CGI是一个很古老的技术,后来随着java servlet技术的兴起,在生产场景已经没有CGI的一点空间了,但它的灵活,便捷正好用在测试环境上。
tomcat和Apache等中间件已经内置了CGI功能,只是默认是非启用状态。此处以tomcat为例,配置CGI接口。
修改点1、在Tomcat的 conf/web.xml 中释放下面CGI相关的两段内容
第一段:
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>WEB-INF/cgi</param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
第二段:
<servlet-mApping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>
修改点2、在Tomcat的 conf/context.xml 中给标签增加属性。
在</Context>标签中添加属性 privileged = "true",因为默认情况下Tomcat是不允许web应用使用容器内的Servlet的,web应用只能使用自己项目的Servlet。
tomcat中开启CGI配置时,没有修改文件路径和访问路径,那空项目就按照默认路径创建目录即可。
在tomcat路径下,直接 mkdir -p webapps/test/WEB-INF/cgi,创建CGI项目目录完毕。
然后在webapps/test/WEB-INF/cgi路径下创建一个文件a,a的内容如下
#!/bin/bash
echo "Content-Type: text/plAIn"
echo
#上面内容是CGI脚本格式,必须存在
#下面内容是自定义要执行的动作
echo "Today is:"
date
http://localhost:8080/test/cgi-bin/a
4.1、实际场景
此时,CGI接口已经配置完毕了,尽管功能已经完毕,但还是不满足实际的使用场景,现在的一个接口只对应一个功能,不能复用。要满足实际的使用场景,就要参数化,传递的参数可以是脚本名称,机器的ip,服务名称,进程名称等等,这样接口的通用性就大大增加了。
4.2、初步解决方案
若想脚本参数化就要解决服务器端的传参和url中传参不一致的问题。url中使用“&”和“参数名=参数值”的传参形式,而服务器端是使用的是空格+直接参数值得形式。需要在执行的a脚本前,先经过一个转换脚本,转换脚本需要先切割url,分成几部分,取出参数和执行的a脚本,再重新拼在一起来执行,那就变成url需要先访问转换脚本,把实际的a脚本和参数都作为参数传进来,处理流程变复杂了。
4.3、网上一个神脚本
直到后来在互联网上最终找到了一个完美的解决方案。找到了一个名字叫“proccgi.sh”的脚本,脚本里的注释中描述是 Frank Pilhofer在1995年写的。我原封不动的拿过来使用了(脚本下载:链接:
https://pan.baidu.com/s/1oZbN13Eog3OKld93f6hEkw?pwd=chen
提取码:chen)。这个脚本设计的很巧妙,它不在传输中间处理url再拼接,而是把url直接都传进执行的a脚本里,然后在a脚本中利用了“eval”命令的的二次扫描功能,扫描出需要的参数,然后把参数放一个特殊的key-value形式的环境变量里,使用的时候直接从环境变量里面去取。
例如:
url:http://localhost:8080/test/cgi-bin/a?ip=115&servername=customer&thread=aabbcc
a脚本改造如下:
#!/bin/bash
eval `proccgi.sh $*` # 解析参数
echo "Content-Type: text/plain"
echo
# ############
echo $FORM_ip
echo $FORM_servername
echo $FORM_thread
有以下几种情况:
1、对页面展示无样式要求的,接口链接直接新开浏览器窗口,接口返回的数据会直接显示在浏览器中。
2、页面有格式的,需要通过ajax触发接口,接口返回值通过innerhtml直接填充到页面的展示区域。
3、对于那些耗时较长的任务,接口在还没有返回值的时候,页面停留在加载状态,此时从页面也无法判断是否出现未知问题。这时可以给页面放一个等待的图片,定义一个标志位给它放一个默认值,然后js轮训判断这个标志位的值,当接口的shell处理完成,接口返回时,要变更标志位的值,轮训发现变更后,就可以把接口返回内容替换掉等待图片全部显示在页面上了。
在定义环境的时候,就尽量定义的通用一些,规律一些。这样可以维护一些通用脚本,通过传入变量参数来做动作。使在服务器中环境维护和定位问题都不再繁琐。