linux 验证码 权限,linux 上验证码无法显示

当前位置:我的异常网» Linux/Unix » linux 上验证码无法显示

linux 上验证码无法显示

www.myexceptions.net  网友分享于:2015-08-26  浏览:678次

linux 下验证码无法显示

验证码无法显示的问题,验证码的代码就是google上查找到的最常见的代码,服务器采用resin部署于linux或unix。不是常见的out.clear()问题,这次的问题发现在一个我压根就没有想到的地方,profile DISPLAY 环境变量。

1) 问题描述:

登录页面等有验证玛显示的页面,通常可以正确显示验证码图片,但是在某些情况下发现验证码图片无法显示,并且目前只发生在linux/unix平台,windows下正常.而且和resin/jdk版本无关.

bug的直接表现是表现为ie下是红叉,firefox下无实现.将验证码图片的地址在ie输入框中输入,则页面报错:

代码

500 Servlet Exception

java.lang.NoClassDefFoundError

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:164)

at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)

at java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141)

at com.asiainfo.aimc.wmail.action.CreateImageServlet.doGet(CreateImageServlet.java:104)

这里的java.lang.NoClassDefFoundError 极其误导人,一直以为是CLASSPATH或者jar包的问题,所以反复检查resin和jdk版本。

始终无法找到问题,只好尝试追查jdk源码,看到底发生了什么。

2) jdk源码追查

调用的servlet:

BufferedImage bi = new BufferedImage(...)

Graphics2D g = bi.createGraphics();

查jdk: BufferedImage.createGraphics():

GraphicsEnvironment env =

GraphicsEnvironment.getLocalGraphicsEnvironment();

再查GraphicsEnvironment.getLocalGraphicsEnvironment:

String nm = (String) java.security.AccessController.doPrivileged

(new sun.security.action.GetPropertyAction

("java.awt.graphicsenv", null));

......

localEnv = GraphicsEnvironment) Class.forName(nm).newInstance();

......

问题应该和nm有关,这里明显是一个类似工厂模式的设计,"java.awt.graphicsenv"到nm 然后Class.forName() 生成GraphicsEnvironment对象。

由于代码在jdk中,不方便修改,因此单独将这些代码提出来到简单的测试类 Test.java:

3) 测试代码分析

代码

public class Test {

public static void main(String[] args) {

String nm = (String) java.security.AccessController.doPrivileged

(new sun.security.action.GetPropertyAction

("java.awt.graphicsenv", null));

System.out.println(nm);

try {

Class.forName(nm).newInstance();

} catch (Throwable e) {

System.out.println("error=" + e.getClass().getName());

e.printStackTrace();

}

}

}

在windows平台下运行,结果正常,打印:

sun.awt.Win32GraphicsEnvironment

将代码放到出问题的resin安装所在的linux平台,手工编译运行:

javac Test.java

java -cp . Test

报错,打印为:

代码

sun.awt.X11GraphicsEnvironment

Throwable=java.lang.InternalError

java.lang.InternalError: Can't connect to X11 window server using '10.3.18.16' as the value of the DISPLAY variable.

at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)

at sun.awt.X11GraphicsEnvironment.access$000(X11GraphicsEnvironment.java:53)

at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:142)

at java.security.AccessController.doPrivileged(Native Method)

at sun.awt.X11GraphicsEnvironment.(X11GraphicsEnvironment.java:131)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:164)

at Test.main(Test.java:13)

从错误信息" Can't connect to X11 window server using '10.3.18.16' as the value of the DISPLAY variable."来看,和DISPLAY环境变量有关

执行unset再运行可以发现问题消失:

$> unset DISPLAY

$> java -cp . Test

sun.awt.X11GraphicsEnvironment

$>

在此情况下(unset DISPLAY )下重新启动resin,发现验证码可以正常显示。

4) 解决的方法:

必须保证resin运行时DISPLAY 环境变量没有设置,如果resin运行的环境有其他要求必须使用DISPLAY,则可以在运行resin前使用unset清除. 建议的简单而有效的方法是直接修改resin/bin/httpd.sh文件,在第二行(具体行数无所谓,但必须在最后一行前)插入:

#! /bin/sh

unset DISPLAY

#....

5)疑惑

1. Can't connect to X11 window server using '10.3.18.16' as the value of the DISPLAY variable

为什么要去连X11 window server ?不懂

2. 从Test.java运行看抛出的是Error : java.lang.InternalError,但是页面上显示的是java.lang.NoClassDefFoundError,看了看源代码也没有发现先catch 后throws的错误处理,不清楚这里的具体处理,不方便继续追查,作罢。

这个是可能因为awt中用到了一些与平台有关的东西,当在类unix系统下时使用了xwindow的有关内容,你需要启动你的xserver   并且需要对用户开放连接xserver的权限,具体如下

启动xserver

initx

开放权限

xhost   +

另外如果系统没有DISPLAY设置的话,还需要export   DISPLAY=0

还是不行,再想办法.

package com.genius.util;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.util.Random;

import javax.imageio.ImageIO;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.mvc.Controller;

public final class ValidateImage implements Controller {

public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

HttpSession session = request.getSession();

//在内存中创建图象

int iWidth = 70, iHeight = 16;

BufferedImage image = new BufferedImage(iWidth, iHeight,

BufferedImage.TYPE_INT_RGB);

//获取图形上下文

Graphics g = image.getGraphics();

//设定背景色

g.setColor(Color.white);

g.fillRect(0, 0, iWidth, iHeight);

//画边框

g.setColor(Color.black);

g.drawRect(0, 0, iWidth - 1, iHeight - 1);

//取随机产生的认证码(4位数字)

String rand = request.getParameter("rand");

rand = rand.substring(0, rand.indexOf("."));

switch (rand.length()) {

case 1:

rand = "000" + rand;

break;

case 2:

rand = "00" + rand;

break;

case 3:

rand = "0" + rand;

break;

default:

rand = rand.substring(0, 4);

break;

}

//将认证码存入SESSION

session.setAttribute("rand", rand);

//将认证码显示到图象中

g.setColor(Color.black);

g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

g.drawString(rand, 10, 15);

//随机产生200个干扰点,使图象中的认证码不易被其它程序探测到

Random random = new Random();

for (int iIndex = 0; iIndex < 200; iIndex++) {

int x = random.nextInt(iWidth);

int y = random.nextInt(iHeight);

g.drawLine(x, y, x, y);

}

//图象生效

g.dispose();

//输出图象到页面

ImageIO.write(image, "JPEG", response.getOutputStream());

return new ModelAndView();

}

}

解决方案2:我把它修改为

package com.genius.util;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.io.IOException;

import java.util.Random;

import javax.imageio.ImageIO;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.mvc.Controller;

import com.sun.image.codec.jpeg.JPEGCodec;

import com.sun.image.codec.jpeg.JPEGImageEncoder;

public final class ValidateImage implements Controller {

public ModelAndView handleRequest(HttpServletRequest request,

HttpServletResponse response) throws ServletException, IOException {

HttpSession session = request.getSession();

//在内存中创建图象

int iWidth = 70, iHeight = 16;

BufferedImage image = new BufferedImage(iWidth, iHeight,

BufferedImage.TYPE_INT_RGB);

//获取图形上下文

Graphics g = image.getGraphics();

//设定背景色

g.setColor(Color.white);

g.fillRect(0, 0, iWidth, iHeight);

//画边框

g.setColor(Color.black);

g.drawRect(0, 0, iWidth - 1, iHeight - 1);

//取随机产生的认证码(4位数字)

String rand = request.getParameter("rand");

rand = rand.substring(0, rand.indexOf("."));

switch (rand.length()) {

case 1:

rand = "000" + rand;

break;

case 2:

rand = "00" + rand;

break;

case 3:

rand = "0" + rand;

break;

default:

rand = rand.substring(0, 4);

break;

}

//将认证码存入SESSION

session.setAttribute("rand", rand);

//将认证码显示到图象中

g.setColor(Color.black);

g.setFont(new Font("Times New Roman", Font.PLAIN, 18));

g.drawString(rand, 10, 15);

//随机产生200个干扰点,使图象中的认证码不易被其它程序探测到

Random random = new Random();

for (int iIndex = 0; iIndex < 200; iIndex++) {

int x = random.nextInt(iWidth);

int y = random.nextInt(iHeight);

g.drawLine(x, y, x, y);

}

//图象生效

g.dispose();

//输出图象到页面

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(response.getOutputStream());

encoder.encode(image);

return new ModelAndView();

}

}

修改后成功,,,

当然我们建立一个linux服务器如BBS等。出现验证码不能显示,

解决方案:

1 rpm -qa |grep php-gd 查看是否安装GD库。如果没有则安装GD库rpm -ivh php-gd-*

(*表示GD库的版本,一般这个软件安装光盘中都能找到)。

2 rpm-qa |grep lib-jpeg 查看是否安装这个软件,如果没有安装。则安装这个软件

后话:在linux系统中有很多的问题是因为没有安装对应的包。或者安装的包是错误

版本不一样。如果你的硬盘空间够大建议安装所有的包。

文章评论

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值