章节索引
Motivation
通过近期收到的反馈和自己的经历,我觉得有必要写这么一篇博文,记录一些由服务器和PC之间的差异引起的不好判断的问题、其原因及其解决方法。
异常1:访问Servlet报错404,排除了各种错误的可能,仍不能正确访问
安全组策略
简单地说就相当于一道防火墙,我们可以自己设定过滤规则。还可以进一步的理解为一套黑白名单系统。
之所以提到安全组策略,是因为,我们遇上这个问题的一个可能就是,云服务器的安全组策略中没有允许80端口或者8080端口访问。
以阿里云服务器为例,以下是操作步骤:
①登录阿里云官方网站,点击右上角的控制台
②点击左侧“云服务器ECS”选项卡
③点击下方自己的云服务器实例
④点击右侧“管理”
⑤点击左侧二级菜单中的“本实例安全组”
⑥点击右侧“配置规则”
⑦在此时弹出的页面中,选择左上方“入方向”选项卡
在列表中的第三行,看是否开放了80或8080端口,如果没有开放,至少可以说明你服务器连接不通的原因之一就在这了。否则,回去继续检查代码的问题。
⑧如果上一步你没有看到80或8080端口,点击页面右上方“添加安全组规则”按钮
⑨按照下图配置即可,之后按右下角“确定”按钮
到这里,安全规则就添加完了,你也可以照猫画虎开放其他必要的端口,然后再测试一下,可能就通了,或者变了其他的报错信息,再具体排除。
异常2:用自己实现的MD5加密算法对用户密码进行加密,发现相同的密码明文在PC(开发用的电脑)上和服务器端得到的密文(即散列值)不同
加密函数代码如下:
public static String getCiphertext(String password) {
try {
byte[] btPassword = password.getBytes();
// 获得MD5摘要算法的 MessageDigest 对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
// 使用指定的字节更新摘要
md5.update(btPassword);
// 获得密文
byte[] binaryCiphertext = md5.digest();
// 把密文转换成十六进制的字符串形式
return toString(binaryCiphertext);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
当执行以下代码时:
String palinText = "1234567890";
String cipherText = getCiphertext(palinText);
System.out.println(cipherText);
在服务器端得到的输出结果是:
28C2596CF7EFD7548B02854ABC210650
而PC上得到的输出结果是:
F54F990C541048704B7EB806A703DE04
这就很困惑了,在没写注册功能的时候,单独测试登录功能就比较麻烦,因为手动给数据库里填的值时机登录的时候验证通不过,暂时留着个已知Bug不管也很是不爽。
经过一番搜索,终于在一篇问答帖中找到了来自大神的答案:
关键在于
byte[] btPassword = password.getBytes();
getBytes()这个方法应该传入一个指定的字符集,如"UTF-8",否则会根据当前应用环境上下文中的字符集来编码,造成差异。
将这行代码改为:
byte[] btPassword = password.getBytes("UTF-8");
就可以发现,无论在什么环境下,相同明文经过MD5之后得到的散列值是一致的。
异常3:javax.crypto.BadPaddingException:Given final block not properly padded.
情境: 在Windows系统下运行正常的DES解密函数,部署到Linux服务器上之后报上述错误。
异常代码段:
SecureRandom secureRandom = new SecureRandom(SECRET_KEY.getBytes());
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(secureRandom);
key = keyGenerator.generateKey();
触发异常的原因: SecureRandom 的实现依赖操作系统本身的內部状态,该实现在 windows 上每次生成的 key 都相同,但是在Solaris 或部分Linux 系统上则不同。
解决方案: 先调用getInstance
方法,然后调用setSeed
方法。
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(SECRET_KEY.getBytes());
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(secureRandom);
key = keyGenerator.generateKey();
异常4:org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions SQL Error: 1146, SQLState: 42S02
情境: 在Linux服务器下部署工程之后,访问时发生上述异常。
触发异常的原因: 操作系统的大小写敏感性决定数据库和表命名的大小写敏感,这就意味着数据库和表名在 Windows 中是大小写不敏感的,而在大多数类型的 Unix/Linux 系统中是大小写敏感的。
解决方案: 发现数据库中的对应表名是user
,而SQL语句中写的是User
,全部改成小写。
后记
自己的PC和服务器之间、Windows操作系统和Linux操作系统之间都存在着许多差异,这就会造成许多意料之外的异常,再次遇到的概率也很高,因此值得记录下来。