vue3 封装api 接收后台接口验证码图片 响应失败

文章讲述了如何在Java中创建一个名为ValidateCode的类,用于生成包含随机字符的验证码图片,并提供两种方式返回:直接图片和Base64编码字符串,同时展示了与SpringMVC集成和前端axios请求的相关代码.
摘要由CSDN通过智能技术生成
package com.example.demo.domain;


import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

//  生成随机验证码
public class ValidateCode {

    private static Random random = new Random();
    private int width = 160;// 宽
    private int height = 40;// 高
    private int lineSize = 30;// 干扰线数量
    private int stringNum = 4;//随机产生字符的个数

    private String randomString = "0123456789abcdefghijklmnopqrstuvwxyz";

    private final String sessionKey = "RANDOMKEY";


    /*
     *  获取字体
     */
    private Font getFont() {
        return new Font("Times New Roman", Font.ROMAN_BASELINE, 40);
    }

    /*
     *  获取颜色
     */
    private static Color getRandomColor(int fc, int bc) {

        fc = Math.min(fc, 255);
        bc = Math.min(bc, 255);

        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 12);

        return new Color(r, g, b);
    }

    /*
     *  绘制干扰线
     */
    private void drawLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(20);
        int yl = random.nextInt(10);
        g.drawLine(x, y, x + xl, y + yl);
    }

    /*
     *  获取随机字符
     */
    private String getRandomString(int num) {
        num = num > 0 ? num : randomString.length();
        return String.valueOf(randomString.charAt(random.nextInt(num)));
    }

    /*
     *  绘制字符串
     */
    private String drawString(Graphics g, String randomStr, int i) {
        g.setFont(getFont());
        g.setColor(getRandomColor(108, 190));
        System.out.println(random.nextInt(randomString.length()));
        String rand = getRandomString(random.nextInt(randomString.length()));
        randomStr += rand;
        g.translate(random.nextInt(3), random.nextInt(6));
        g.drawString(rand, 40 * i + 10, 25);
        return randomStr;
    }

    /*
     *  生成随机图片
     */
    public void getRandomCodeImage(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);
        g.setColor(getRandomColor(105, 189));
        g.setFont(getFont());

        // 绘制干扰线
        for (int i = 0; i < lineSize; i++) {
            drawLine(g);
        }

        // 绘制随机字符
        String random_string = "";
        for (int i = 0; i < stringNum; i++) {
            random_string = drawString(g, random_string, i);
        }

        System.out.println(random_string);

        g.dispose();

        session.removeAttribute(sessionKey);
        session.setAttribute(sessionKey, random_string);

        String base64String = "";
        try {
            //  直接返回图片
            ImageIO.write(image, "PNG", response.getOutputStream());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     *  生成随机图片,返回 base64 字符串
     */
    public String getRandomCodeBase64(HttpServletRequest request, HttpServletResponse response) {
        try {
            HttpSession session = request.getSession();
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
            Graphics g = image.getGraphics();
            try {
                g.fillRect(0, 0, width, height);
                g.setColor(getRandomColor(105, 189));
                g.setFont(getFont());

                // 绘制干扰线
                for (int i = 0; i < lineSize; i++) {
                    drawLine(g);
                }

                // 绘制随机字符
                String random_string = "";
                for (int i = 0; i < stringNum; i++) {
                    random_string = drawString(g, random_string, i);
                }

                g.dispose();

                session.removeAttribute(sessionKey);
                session.setAttribute(sessionKey, random_string);

                // 将图片转换为Base64编码的字符串
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ImageIO.write(image, "PNG", bos);
                byte[] bytes = bos.toByteArray();
                Base64.Encoder encoder = Base64.getEncoder();
                return encoder.encodeToString(bytes);
            } finally {
                // 释放图形上下文资源
                g.dispose();
            }
        } catch (Exception e) {
            // 记录异常信息,确保异常不影响系统的其他部分
            e.printStackTrace();
            // 可以设置一个适当的HTTP状态码,如500,表示服务器内部错误
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            // 返回一个错误信息的Base64字符串或者null
            return null;
        }
    }
}
@Resource  
private UserService userService;
    @GetMapping("/validate")
    @ResponseBody
    public void getCaptcha(HttpServletRequest request, HttpServletResponse response) {
        response.setContentType("image/png");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Expires", "0");
        response.setHeader("Pragma", "no-cache");
        ValidateCode validateCode = new ValidateCode();
        try {
            // 根据需要选择调用以下两个方法中的一个
            validateCode.getRandomCodeImage(request, response); // 返回图片

//             validateCode.getRandomCodeBase64(request, response); // 返回Base64字符串
        } catch (Exception e) {
            // 使用日志框架记录异常
            // log.error("Error generating captcha", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 设置状态码为500
            try {
                response.getWriter().write("Error generating captcha"); // 可选:向客户端返回错误信息
            } catch (IOException ioException) {
                // log.error("Error writing error message to response", ioException);
            }
        }
    }

我这段代码定义了一个名为 ValidateCode 的 Java 类,其主要用途是生成一个包含随机字符的验证码图片。这个类我提供了两种方法来生成验证码:一种是直接生成图片并发送到 HttpServletResponse 的输出流中,另一种是生成图片并将其转换为 Base64 编码的字符串  然后我通过控制器 通过get 方法 将 图片的 响应内容 设置为图片的形式返回给前端 

测试swagger:

在swagger中能够正常返回 图片 

log打印没问题 :

然后我在viter中设置了后台的端口代理 通过/api地址 访问后台8301服务器地址

import { defineConfig } from 'vite'

import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/

export default defineConfig({

  plugins: [vue()],

  resolve: {

    alias: {

      '@': './src' // 直接使用相对路径

    }

  },

  server: {

    proxy: {

      '/api': {

        target: 'http://localhost:8301', // 后台服务器的地址

        changeOrigin: true, // 改变源,避免一些浏览器的同源策略限制

        rewrite: (path) => path.replace(/^\/api/, '') // 重写路径,移除 '/api' 前缀

      }

    }

  }

})

设置axios 实列 并配置拦截器 前面在viter设置了 代理   通过aixos 访问默认的baseURl :api来直接访问后台服务器地址:

// 导入 axios 依赖

import axios from 'axios'

// 定义baseUrl

const baseURL = '/api'

// 创建实例

const request = axios.create({

  baseURL: baseURL,

  responseType: 'arraybuffer', // 设置响应类型为blob,以便处理二进制数据

  withCredentials: true // 如果需要跨域请求时携带cookie,可以设置这个选项

})

// 添加响应拦截器

request.interceptors.response.use(

  (result) => {

    return result.data

  },

  (err) => {

    alert('服务异常')

    return Promise.reject(err)

  }

)

export default request

设置访问对应后台服务器 接口地址 并配置参数

import instance from './request'

//一般情况下,接口类型会放到一个文件

// 下面两个TS接口,表示要传的参数

interface ReqLogin {

  name: string

  paw: string

}

interface ReqStatus {

  id: string

  navStatus: string

}

// Res是返回的参数,T是泛型,需要自己定义,返回对数统一管理***

type Res<T> = Promise<ItypeAPI<T>>

// 一般情况下响应数据返回的这三个参数,

// 但不排除后端返回其它的可能性,

interface ItypeAPI<T> {

  data: T //请求的数据,用泛型

  msg: string | null // 返回状态码的信息,如请求成功等

  code: number //返回后端自定义的200,404,500这种状态码

}

interface CaptchaResponse {

  type: Blob

  captchaSrc: string // 验证码图片的 URL

}

// 定义一个表示图片Blob的类

// post请求 ,没参数

export const LogoutAPI = (): Res<null> => instance.post('/admin/logout')

// post请求,有参数,如传用户名和密码

export const loginAPI = (data: ReqLogin): Res<string> => instance.post('/admin/login', data)

// post请求 ,没参数,但要路径传参

export const StatusAPI = (data: ReqStatus): Res<null> =>

  instance.post(`/productCategory?ids=${data.id}&navStatus=${data.navStatus}`)

//  get请求,没参数,

export const FlashSessionListApi = (): Res<null> => instance.get('/flashSession/list')

// get请求,有参数,路径也要传参  (也可能直接在这写类型,不过不建议,大点的项目会维护一麻烦)

export const ProductCategoryApi = (params: { parentId: number }): any =>

  instance.get(`/productCategory/list/${params.parentId}`, { params })

// get请求,有参数,(如果你不会写类型也可以使用any,不过不建议,因为用了之后 和没写TS一样)

export const AdminListAPI = (params: any): any => instance.get('/admin/list', { params })

// export const getCaptchaApi = (): Promise<Res<CaptchaResponse>> => {

//   return instance.get('/user/validate')

// }

// export const getCaptchaApi = (): Res<CaptchaResponse> => {

//   return instance.post<CaptchaResponse>('/user/validate', {}, {

//     responseType: 'arraybuffer', // 告诉 Axios 返回类型为 ArrayBuffer

//   });

interface CaptchaResponse {

  captchaSrc: string // 这里应该是base64字符串

}

// 修改getCaptchaApi,使其返回Promise<Res<CaptchaResponse>>

export const getCaptchaApi = (): Promise<Res<CaptchaResponse>> => {

  return instance.get('/user/validate', {

    responseType: 'blob' // 因为返回的是字符串,所以设置responseType为text

  })

}

核心点:

这里我将api 对应的后台验证码图片 访问的接口地址 设置好 并将类型设置为blob 图片类型接收2进制的数据图片 

export const getCaptchaApi = (): Promise<Res<CaptchaResponse>> => {

  return instance.get('/user/validate', {

    responseType: 'blob' // 因为返回的是字符串,所以设置responseType为text

  })

设置响应数据 获取后台接口的验证码图片 

const captchaSrc = ref('')

const refreshCaptcha = async () => {

  try {

    let response = await getCaptchaApi()

    if (response.code === 200 && response.data instanceof Blob) {

      // 将 Blob 对象转换为图片 URL 并更新到 captchaSrc

      captchaSrc.value = URL.createObjectURL(response.data)

    } else {

      throw new Error('获取验证码失败')

    }

  } catch (error) {

    console.error('请求验证码失败:', error)

    alert('请求验证码失败,请稍后再试。')

    // 修正:使用箭头函数来确保 refreshCaptcha 会在3秒后执行

    setTimeout(() => refreshCaptcha(), 3000) // 3秒后重试

  }

}

 <el-image

         

            @click="refreshCaptcha"

            :src="captchaSrc"

            style="width: 105px; margin-left: 40px"

          />

结果:

这是什么问题 求各位大佬解迷

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值