Java源码剖析之server2008上拉不出验证码-阿里云开发者社区

开发者社区> 沉默王二> 正文

Java源码剖析之server2008上拉不出验证码

简介: Java源码剖析之server2008上拉不出验证码
+关注继续查看

Java源码剖析之server2008上拉不出验证码


初步调查


项目已经成功运行了很多个版本,在windows server 2003上运行OK。

在windows7上运行也OK。

但偏偏到了windows server 2008上却拉不出来验证码,真是引起了我极大的兴趣!


主要的异常信息如下:

ERROR 2015-11-25 10:25:44,061 com.honzh.socket.server.communicate.biz.CodeBiz: Can't create output stream!
javax.imageio.IIOException: Can't create output stream!
    at javax.imageio.ImageIO.write(Unknown Source)

Caused by: javax.imageio.IIOException: Can't create cache file!
    at javax.imageio.ImageIO.createImageOutputStream(Unknown Source)
    ... 11 more
Caused by: java.io.IOException: 系统找不到指定的路径。
    at java.io.WinNTFileSystem.createFileExclusively(Native Method)
    at java.io.File.checkAndCreate(Unknown Source)
    at java.io.File.createTempFile0(Unknown Source)
    at java.io.File.access$100(Unknown Source)
    at java.io.File$1.createTempFile(Unknown Source)
    at sun.misc.IOUtils.createTempFile(Unknown Source)
    at javax.imageio.stream.FileCacheImageOutputStream.<init>(Unknown Source)
    at com.sun.imageio.spi.OutputStreamImageOutputStreamSpi.createOutputStreamInstance(Unknown Source)
    ... 12 more

透过这个异常信息,我开始追本溯源,当然就是翻看源码了。


先看ImageIO.write内容,可以定位到是createImageOutputStream抛出了IIOException异常。

    public static boolean write(RenderedImage im,
                                String formatName,
                                OutputStream output) throws IOException {
        if (output == null) {
            throw new IllegalArgumentException("output == null!");
        }
        ImageOutputStream stream = null;
        try {
            stream = createImageOutputStream(output);
        } catch (IOException e) {
            throw new IIOException("Can't create output stream!", e);
        }

        boolean val;
        try {
            val = write(im, formatName, stream);
        } finally {
            stream.close();
        }
        return val;
    }


再看createImageOutputStream方法,可以定位到ImageOutputStreamSpi类的createOutputStreamInstance方法


try {
                    return spi.createOutputStreamInstance(output,
                                                          usecache,
                                                          getCacheDirectory());
                } catch (IOException e) {
                    throw new IIOException("Can't create cache file!", e);
                }


然后,我们定位到OutputStreamImageOutputStreamSpi的createOutputStreamInstance方法,

OutputStreamImageOutputStreamSpi继承了ImageOutputStreamSpi类
    public ImageOutputStream createOutputStreamInstance(Object output,
                                                        boolean useCache,
                                                        File cacheDir)
        throws IOException {
        if (output instanceof OutputStream) {
            OutputStream os = (OutputStream)output;
            if (useCache) {
                return new FileCacheImageOutputStream(os, cacheDir);
            } else {
                return new MemoryCacheImageOutputStream(os);
            }
        } else {
            throw new IllegalArgumentException();
        }
    }


OK,关键的地方来了,我们继续挖,直到挖到FileCacheImageOutputStream构造方法。


   

public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
        throws IOException {
        if (stream == null) {
            throw new IllegalArgumentException("stream == null!");
        }
        if ((cacheDir != null) && !(cacheDir.isDirectory())) {
            throw new IllegalArgumentException("Not a directory!");
        }
        this.stream = stream;
        this.cacheFile =
            sun.misc.IOUtils.createTempFile("imageio", ".tmp", cacheDir);
        this.cache = new RandomAccessFile(cacheFile, "rw");
        this.closeAction = StreamCloser.createCloseAction(this);
        StreamCloser.addToQueue(closeAction);
    }


到这里,我想你需要看一看该方法的javadoc了。


Constructs a FileCacheImageOutputStream that will write to a given outputStream.

A temporary file is used as a cache. If cacheDiris non-null and is a directory, the file will be created there. If it is null, the system-dependent default temporary-file directory will be used (see the documentation for File.createTempFile for details).

让我们去看File.createTempFile方法,这时候就需要上java api帮助文档了!


createTempFile

public static File createTempFile(String prefix,

String suffix,

File directory)

throws IOException在指定目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。如果此方法成功返回,则可以保证:

由返回的抽象路径名表示的文件在此方法被调用之前不存在。

此方法及其所有变体都不会在虚拟机的当前调用中再次返回相同的抽象路径名。

此方法只提供了临时文件的部分功能。要安排自动删除此方法创建的文件,可使用 deleteOnExit() 方法。

prefix 参数至少必须是三个字节长。建议前缀使用一个短的、有意义的字符串,比如 “hjb” 或 “mail”。suffix 参数可以为 null,在这种情况下,将使用后缀 “.tmp”。

要创建新文件,可能首先要调整前缀和后缀,使其满足底层平台的限制。如果前缀太长,则将它截断,但前三个字符将始终保留。如果后缀太长,则将它截断,但如果它以句点字符 (‘.’) 开始,则该句点以及后跟的前三个字符将始终保留。进行了这些调整后,通过连接前缀、五个或更多个内部生成的字符以及后缀,便生成了新文件的名称。

如果 directory 参数为 null,则使用与系统有关的默认临时文件目录。默认临时文件目录由系统属性 java.io.tmpdir 指定。在 UNIX 系统上,此属性的默认值通常是 “/tmp” 或 “/var/tmp”;在 Microsoft Windows 系统上,该值通常是 “C:\WINNT\TEMP”。在调用 Java 虚拟机时,可为此系统属性提供不同的值,但不保证使用程序更改此属性会对此方法使用的临时目录产生影响。

参数:

prefix - 用于生成文件名的前缀字符串;必须至少是三字符长

suffix - 用于生成文件名的后缀字符串;可以为 null,在这种情况下,将使用后缀 “.tmp”

directory - 将创建的文件所在的目录;如果使用默认临时文件目录,则该参数为 null

返回:

表示新建空文件的抽象路径名

抛出:

IllegalArgumentException - 如果 prefix 参数包含的字符少于三个

IOException - 如果无法创建文件

SecurityException - 如果存在安全管理器,且其 SecurityManager.checkWrite(java.lang.String) 方法不允许创建文件

注意,这里告诉我们去看一下windows的C:\WINNT\TEMP目录。


WINNT是啥玩意,我反正是不太清楚,问问度娘:


Microsoft Windows NT(New Technology)是Microsoft在1993年推出的面向工作站、网络服务器和大型计算机的网络操作系统,也可做PC操作系统。它与通信服务紧密集成,基于OS/2 NT基础编制。OS/2由微软和IBM联合研制,分为微软的Microsoft OS/2 NT与IBM的IBM OS/2。协作后来不欢而散,IBM继续向市场提供先前的OS/2版本,微软则把自己的OS/2 NT的名称改为Windows NT,即第一代的Windows NT 3.1。

大概可能是以上的意思。


然后,我对比了一下win7和windows server 2008的

image.png


很遗憾,没有找到我想要的,不高兴!


继续探索


再回过头来看看,发现这句关键字:

默认临时文件目录由系统属性 java.io.tmpdir 指定


写个程序测试下


public class Test {
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.io.tmpdir"));
    }
}


系统 输出

win7 C:\Users\abc\AppData\Local\Temp\

server 2008 C:\Users\ADMINI~1\AppData\Local\Temp\2\



顺着目录找下来,windows 2008的大概目录应该是C:\Users\Administrator\AppData\Local,但是也找不下去,没有找到2。


先新建一个2目录试试,结果发现验证码可以输出了!

image.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
2902 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
11116 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10761 0
使用OpenApi弹性释放和设置云服务器ECS释放
云服务器ECS的一个重要特性就是按需创建资源。您可以在业务高峰期按需弹性的自定义规则进行资源创建,在完成业务计算的时候释放资源。本篇将提供几个Tips帮助您更加容易和自动化的完成云服务器的释放和弹性设置。
11997 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
8990 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
7368 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
21832 0
+关注
沉默王二
微信搜索「沉默王二」,回复关键字「00」获取硬核计算机基础资料。
1084
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载