Captcha验证码不显示

1,875 阅读2分钟

Captcha验证码不显示

今天在做自己项目的登录功能时出现了验证码能正常获取到,但不能在界面上显示的问题.

1.前端代码

html:
<el-form-item prop="captcha">
                      <el-input class="login-input-code" v-model="dataForm.captcha" placeholder="验证码" clearable autosize>
                      </el-input>
                  <el-image :span="12" class="login-img-verify-code" :src="captchaPath" @click="getCaptcha()" alt=""></el-image>
                </el-form-item>

js:
<script>
methods: {
// 获取验证码
    getCaptcha () {
      this.dataForm.uuid = this.getUUID()
      this.captchaPath = this.$axios.get(`/captcha.jpg?uuid=${this.dataForm.uuid}`, {
        //responseType: 'blob'
      }).toString()
    },
}
</script>

2.后端代码

Controller层:

import com.ark.fitnesshub.common.utils.R;
import com.ark.fitnesshub.core.entity.UserEntity;
import com.ark.fitnesshub.core.form.LoginForm;
import com.ark.fitnesshub.core.form.RegisterForm;
import com.ark.fitnesshub.core.service.CaptchaService;
import com.ark.fitnesshub.core.service.UserService;
import com.ark.fitnesshub.core.service.UserTokenService;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
@CrossOrigin
@RestController
//@RequestMapping("/entry")
public class EntryController {
    @Autowired
    private CaptchaService captchaService;
    
    /**
     * 验证码
     */
    @GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response, String uuid)throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //获取图片验证码
        BufferedImage image = captchaService.getCaptcha(uuid);

        ServletOutputStream out = response.getOutputStream();

        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }
}

Service层(省略Service接口):

import com.ark.fitnesshub.common.exception.RRException;
import com.ark.fitnesshub.common.utils.DateUtils;
import com.ark.fitnesshub.common.utils.PageUtils;
import com.ark.fitnesshub.common.utils.Query;
import com.ark.fitnesshub.core.dao.CaptchaDao;
import com.ark.fitnesshub.core.entity.CaptchaEntity;
import com.ark.fitnesshub.core.service.CaptchaService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.code.kaptcha.Producer;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("captchaService")
public class CaptchaServiceImpl extends ServiceImpl<CaptchaDao, CaptchaEntity> implements CaptchaService {
    @Autowired
    private Producer producer;
    
    @Override
    public BufferedImage getCaptcha(String uuid) {
        if(StringUtils.isBlank(uuid)){
            throw new RRException("uuid不能为空");
        }
        //生成文字验证码
        String code = producer.createText();

        CaptchaEntity captchaEntity = new CaptchaEntity();
        captchaEntity.setUuid(uuid);
        captchaEntity.setCode(code);
        //5分钟后过期
        captchaEntity.setExpireTime(DateUtils.addDateMinutes(new Date(), 5));
        this.save(captchaEntity);
        return producer.createImage(code);
    }
}

Entity层:

@Data
@TableName("captcha")
public class CaptchaEntity {
//	private static final long serialVersionUID = 1L;
	/**
	 * 随机数,非空非自增
	 */
	@TableId(type = IdType.INPUT)
	private String uuid;
	/**
	 * 验证码,非空
	 */
	private String code;
	/**
	 * 过期时间
	 */
	private Date expireTime;
}

3.问题演示

1.前端不报错,能在network中正常显示验证码图片,如下:

image-20210309104609519.png

image-20210309104709849.png

image-20210309104739613.png

但在登录界面上显示加载失败,如下:

image-20210309104840996.png

2.后端Tomcat不报错,debug日志如下:

image-20210309105016929.png

数据也正常存入数据库中的captcha表,如下:

image-20210309105144980.png

我在网上找遍了几乎所有的可能的解决方案,比如在前端的js中将返回的图片流进行定义数据类型ResponseType:' blob' 和'arraybuffer',检查了前后端项目的端口都是对应的(前端项目端口localhost:8081,在main.js文件中的axios的默认请求名为axios.defaults.baseURL = 'http://localhost:8100',后端项目接口为localhost:8100)。

4.问题解决

检查了半天发现是后端对验证码图片的存储问题,将EntryController中的captcha方法中的

response.setHeader("Cache-Control", "no-store,no-cache");

改成:

response.setHeader("Cache-Control", "no-cache");

之后重新加载界面后就可以正常显示验证码图片了,如下:

image-20210310112350192.png

5.总结

改动的原因是验证码生成后需要缓存在服务器中供客户端获取。遇到问题不要慌,冷静分析按图索骥。(本文和SegmentFault社区文章同步更新)