Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密解密

加密效果:

解密后的数据就是正常数据:

后端:使用的是spring-cloud框架,在gateway模块进行操作

        <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version></dependency>

编写一个AES加密的utils

package com.medical.gateway.utils;import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;/*** AES加解密工具类* Rui*/
public class   AESUtil {private static final String ENCODE_RULES = "mjfeng";/*** 加密* 1.构造密钥生成器* 2.根据ecnodeRules规则初始化密钥生成器* 3.产生密钥* 4.创建和初始化密码器* 5.内容加密* 6.返回字符串*/public static String aesEncode(String content) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(ENCODE_RULES.getBytes());keyGenerator.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keyGenerator.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.ENCRYPT_MODE, key);//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码byte[] byteEncode = content.getBytes("utf-8");//9.根据密码器的初始化方式--加密:将数据加密byte[] byteAES = cipher.doFinal(byteEncode);//10.将加密后的数据转换为字符串//这里用Base64Encoder中会找不到包//解决办法://在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。String aesEncode = new String(Base64.getEncoder().encode(byteAES));//11.将字符串返回return aesEncode;} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}/*** 解密* 解密过程:* 1.同加密1-4步* 2.将加密后的字符串反纺成byte[]数组* 3.将加密内容解密*/public static String aesDecode(String content) {try {//1.构造密钥生成器,指定为AES算法,不区分大小写KeyGenerator keygen = KeyGenerator.getInstance("AES");//2.根据ecnodeRules规则初始化密钥生成器//生成一个128位的随机源,根据传入的字节数组SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(ENCODE_RULES.getBytes());keygen.init(128, random);//3.产生原始对称密钥SecretKey originalKey = keygen.generateKey();//4.获得原始对称密钥的字节数组byte[] raw = originalKey.getEncoded();//5.根据字节数组生成AES密钥SecretKey key = new SecretKeySpec(raw, "AES");//6.根据指定算法AES自成密码器Cipher cipher = Cipher.getInstance("AES");//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEYcipher.init(Cipher.DECRYPT_MODE, key);//8.将加密并编码后的内容解码成字节数组byte[] byteContent = Base64.getDecoder().decode(content);/** 解密*/byte[] byteDecode = cipher.doFinal(byteContent);String aesDecode = new String(byteDecode, "utf-8");return aesDecode;} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}/*** 解密* 解密过程:* 1.同加密1-4步* 2.将加密后的字符串反纺成byte[]数组* 3.将加密内容解密*/public static String aesDecodeByKey(String content, String aesKey) {try {byte[] byteContent = Base64.getDecoder().decode(content);SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);/** 解密*/byte[] byteDecode = cipher.doFinal(byteContent);String aesDecode = new String(byteDecode, "utf-8");return aesDecode;} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}/*** 加密* 1.构造密钥生成器* 2.根据ecnodeRules规则初始化密钥生成器* 3.产生密钥* 4.创建和初始化密码器* 5.内容加密* 6.返回字符串*/public static String aesEncodeByKey(String content, String aesKey) {try {SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey.getBytes(), "AES");Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码byte[] byteEncode = content.getBytes("utf-8");//9.根据密码器的初始化方式--加密:将数据加密byte[] byteAES = cipher.doFinal(byteEncode);//10.将加密后的数据转换为字符串//这里用Base64Encoder中会找不到包//解决办法://在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。String aesEncode = new String(Base64.getEncoder().encode(byteAES));//11.将字符串返回return aesEncode;} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();} catch (InvalidKeyException e) {e.printStackTrace();} catch (IllegalBlockSizeException e) {e.printStackTrace();} catch (BadPaddingException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();}//如果有错就返加nulllreturn null;}}

需要AuthFilter,过滤器中加上相关方法,在这个方法的下面开始加

 private ServerHttpRequest getServerHttpRequest(ServerHttpRequest request) {String bodyStr = resolveBodyFromRequest(request);System.out.println("PUT OR POST bodyStr: " + bodyStr);String decode = "";try {if(StringUtils.isEmpty(bodyStr)){return request;}decode = AESUtil.aesDecodeByKey(bodyStr, "MP5v0^zee5Qlgq5V");//解密方法可以自由替换,这里使用AES为例。} catch (Exception e) {e.printStackTrace();}URI uri = request.getURI();DataBuffer bodyDataBuffer = stringBuffer(decode);Flux<DataBuffer> bodyFlux1 = Flux.just(bodyDataBuffer);request = new ServerHttpRequestDecorator(request) {@Overridepublic Flux<DataBuffer> getBody() {return bodyFlux1;}};return request;}private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {//获取请求体Flux<DataBuffer> body = serverHttpRequest.getBody();AtomicReference<String> bodyRef = new AtomicReference<>();body.subscribe(buffer -> {CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());DataBufferUtils.release(buffer);bodyRef.set(charBuffer.toString());});//获取request bodyreturn bodyRef.get();}private DataBuffer stringBuffer(String value) {
//        this.value = value;byte[] bytes = value.getBytes(StandardCharsets.UTF_8);NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);buffer.write(bytes);return buffer;}

然后需要加另一个类ParamsEncryptionFilter

package com.medical.gateway.filter;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;@Component
public class ParamsEncryptionFilter implements GlobalFilter, Ordered {private static final Logger log = LoggerFactory.getLogger(ParamsEncryptionFilter.class);@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {/*** save request path and serviceId into gateway context*/ServerHttpRequest request = exchange.getRequest();HttpHeaders headers = request.getHeaders();// 处理参数MediaType contentType = headers.getContentType();long contentLength = headers.getContentLength();if (contentLength > 0) {if (MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {readBody(exchange, chain);return readBody(exchange, chain);}}return chain.filter(exchange);}/*** default HttpMessageReader*/private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();/*** ReadJsonBody** @param exchange* @param chain* @return*/private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {/*** join the body*/return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {byte[] bytes = new byte[dataBuffer.readableByteCount()];dataBuffer.read(bytes);DataBufferUtils.release(dataBuffer);Flux<DataBuffer> cachedFlux = Flux.defer(() -> {DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);DataBufferUtils.retain(buffer);return Mono.just(buffer);});/*** repackage ServerHttpRequest*/ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic Flux<DataBuffer> getBody() {return cachedFlux;}};/*** mutate exchage with new ServerHttpRequest*/ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();/*** read body string with default messageReaders*/return ServerRequest.create(mutatedExchange, messageReaders).bodyToMono(String.class).doOnNext(objectValue -> {log.debug("[GatewayContext]Read JsonBody:{}", objectValue);}).then(chain.filter(mutatedExchange));});}@Overridepublic int getOrder() {return HIGHEST_PRECEDENCE;}}

还有一个类也需要加入ResponseFilter

package com.medical.gateway.filter;import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;import com.medical.gateway.config.properties.IgnoreWhiteProperties;
import com.medical.gateway.utils.AESUtil;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.List;import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;@Component
public class ResponseFilter implements GlobalFilter, Ordered {private static final Logger log = LoggerFactory.getLogger(ResponseFilter.class);private static Joiner joiner = Joiner.on("");// 排除过滤的 uri 地址,nacos自行添加@Autowiredprivate IgnoreWhiteProperties ignoreWhite;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpRequest.Builder mutate = request.mutate();String url = request.getURI().getPath();String methodValue = request.getMethodValue();ServerHttpResponse originalResponse = exchange.getResponse();DataBufferFactory bufferFactory = originalResponse.bufferFactory();log.info("进入响应拦截");ServerHttpResponse response = exchange.getResponse();DataBufferFactory dataBufferFactory = response.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(response) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {// 获取ContentType,判断是否返回JSON格式数据String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {Flux<? extends DataBuffer> fluxBody = Flux.from(body);//(返回数据内如果字符串过大,默认会切割)解决返回体分段传输return super.writeWith(fluxBody.buffer().map(dataBuffers -> {List<String> list = Lists.newArrayList();dataBuffers.forEach(dataBuffer -> {try {byte[] content = new byte[dataBuffer.readableByteCount()];dataBuffer.read(content);DataBufferUtils.release(dataBuffer);list.add(new String(content, "utf-8"));} catch (Exception e) {log.info("加载Response字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));}});String responseData = joiner.join(list);System.out.println("responseData:"+responseData);String s = AESUtil.aesEncodeByKey(responseData, "MP5v0^zee5Qlgq5V");s =  s.replaceAll("\r\n", "").replaceAll("\n","");byte[] uppedContent = new String(s.getBytes(), Charset.forName("UTF-8")).getBytes();originalResponse.getHeaders().setContentLength(uppedContent.length);return bufferFactory.wrap(uppedContent);}));}}return super.writeWith(body);}};return chain.filter(exchange.mutate().response(decoratedResponse).build());}@Overridepublic int getOrder() {return -2;}private String Bytes2String(byte[] bytes){Charset cs = Charset.forName("UTF-8");ByteBuffer bb = ByteBuffer.allocate(bytes.length);bb.put(bytes).flip();CharBuffer cb = cs.decode(bb);String res = new String(cb.array());return res;}
}

到这里后端代码已经基本完成,下面开始操作前段代码

在utils包下面编写一个AES.js,用于AES加密和解密

    import CryptoJS from "crypto-js";export default {// 加密encrypt(word, keyStr) {keyStr = keyStr ? keyStr : "MP5v0^zee5Qlgq5V";let key = CryptoJS.enc.Utf8.parse(keyStr);let srcs = CryptoJS.enc.Utf8.parse(word);let encrypted = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();},// 解密decrypt(word, keyStr) {keyStr = keyStr ? keyStr : "MP5v0^zee5Qlgq5V";var key = CryptoJS.enc.Utf8.parse(keyStr);var decrypt = CryptoJS.AES.decrypt(word, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return CryptoJS.enc.Utf8.stringify(decrypt).toString();}
};

下面需要注意,我使用的是ruoyi的前段框架,在这里我不能直接将request.js直接替换掉原有的request.js,我是直接手写需要的代码,但是我会给request.js文件放在下面

request.js 仅供参考

import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/shop";
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import AES from '@/utils/AES'let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 10000
})// request拦截器
service.interceptors.request.use(config => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === false// 是否需要防止数据重复提交const isRepeatSubmit = (config.headers || {}).repeatSubmit === falseif (getToken() && !isToken) {config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改}// get请求映射params参数if (config.method === 'get' && config.params) {let url = config.url + '?' + tansParams(config.params);url = url.slice(0, -1);config.params = {};config.url = url;}if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {const requestObj = {url: config.url,data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,time: new Date().getTime()}const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小const limitSize = 5 * 1024 * 1024; // 限制存放数据5Mif (requestSize >= limitSize) {console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')return config;}const sessionObj = cache.session.getJSON('sessionObj')config.data = AES.encrypt(JSON.stringify(config.data))if (sessionObj === undefined || sessionObj === null || sessionObj === '') {cache.session.setJSON('sessionObj', requestObj)} else {const s_url = sessionObj.url;                  // 请求地址const s_data = sessionObj.data;                // 请求数据const s_time = sessionObj.time;                // 请求时间const interval = 1000;                         // 间隔时间(ms),小于此时间视为重复提交if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {const message = '数据正在处理,请勿重复提交';console.warn(`[${s_url}]: ` + message)return Promise.reject(new Error(message))} else {cache.session.setJSON('sessionObj', requestObj)}}}return config
}, error => {console.log(error)Promise.reject(error)
})// 响应拦截器
service.interceptors.response.use(res => {// 未设置状态码则默认成功状态const code = res.data.code || 200;// 获取错误信息const msg = errorCode[code] || res.data.msg || errorCode['default']// 二进制数据则直接返回if (res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer') {return res.data}if (code === 401) {if (!isRelogin.show) {isRelogin.show = true;MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {isRelogin.show = false;store.dispatch('LogOut').then(() => {location.href = '/index';})}).catch(() => {isRelogin.show = false;});}return Promise.reject('无效的会话,或者会话已过期,请重新登录。')} else if (code === 500) {Message({ message: msg, type: 'error' })return Promise.reject(new Error(msg))} else if (code === 601) {Message({ message: msg, type: 'warning' })return Promise.reject('error')} else if (code !== 200) {Notification.error({ title: msg })return Promise.reject('error')} else {if ( res.request.responseURL.indexOf('code') == -1 || res.config.method === 'post' || res.config.method=== 'put'  || res.config.method=== 'delete') {let decrypt = AES.decrypt(res.data);console.log(decrypt)return JSON.parse(decrypt)}return res.data}},error => {console.log('err' + error)let { message } = error;if (message == "Network Error") {message = "后端接口连接异常";} else if (message.includes("timeout")) {message = "系统接口请求超时";} else if (message.includes("Request failed with status code")) {message = "系统接口" + message.substr(message.length - 3) + "异常";}Message({ message: message, type: 'error', duration: 5 * 1000 })return Promise.reject(error)}
)// 通用下载方法
export function download(url, params, filename, config) {downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {transformRequest: [(params) => { return tansParams(params) }],headers: { 'Content-Type': 'application/x-www-form-urlencoded' },responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data);if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text();const rspObj = JSON.parse(resText);const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']Message.error(errMsg);}downloadLoadingInstance.close();}).catch((r) => {console.error(r)Message.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close();})
}export default service

主要编写的地方是--->

引入AES

在这个地方进行加密操作

在这个地方进行解密操作

我的代码放在这里可以和上面的request.js对比

import axios from 'axios'
import { Notification, MessageBox, Message, Loading } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from "@/utils/ruoyi";
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import AES from '@/utils/AES'let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({// axios中请求配置有baseURL选项,表示请求URL公共部分baseURL: process.env.VUE_APP_BASE_API,// 超时timeout: 10000
})// request拦截器
service.interceptors.request.use(config => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === false// 是否需要防止数据重复提交const isRepeatSubmit = (config.headers || {}).repeatSubmit === falseif (getToken() && !isToken) {config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改}// get请求映射params参数if (config.method === 'get' && config.params) {let url = config.url + '?' + tansParams(config.params);url = url.slice(0, -1);config.params = {};config.url = url;}if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {const requestObj = {url: config.url,data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,time: new Date().getTime()}const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小const limitSize = 5 * 1024 * 1024; // 限制存放数据5Mif (requestSize >= limitSize) {console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')return config;}const sessionObj = cache.session.getJSON('sessionObj')config.data = AES.encrypt(JSON.stringify(config.data))if (sessionObj === undefined || sessionObj === null || sessionObj === '') {cache.session.setJSON('sessionObj', requestObj)} else {const s_url = sessionObj.url;                  // 请求地址const s_data = sessionObj.data;                // 请求数据const s_time = sessionObj.time;                // 请求时间const interval = 1000;                         // 间隔时间(ms),小于此时间视为重复提交if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {const message = '数据正在处理,请勿重复提交';console.warn(`[${s_url}]: ` + message)return Promise.reject(new Error(message))} else {cache.session.setJSON('sessionObj', requestObj)}}}return config
}, error => {console.log(error)Promise.reject(error)
})// 响应拦截器
service.interceptors.response.use(res => {// 未设置状态码则默认成功状态const code = res.data.code || 200;// 获取错误信息const msg = errorCode[code] || res.data.msg || errorCode['default']// 二进制数据则直接返回if (res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer') {return res.data}if (code === 401) {if (!isRelogin.show) {isRelogin.show = true;MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {isRelogin.show = false;store.dispatch('LogOut').then(() => {location.href = '/index';})}).catch(() => {isRelogin.show = false;});}return Promise.reject('无效的会话,或者会话已过期,请重新登录。')} else if (code === 500) {Message({ message: msg, type: 'error' })return Promise.reject(new Error(msg))} else if (code === 601) {Message({ message: msg, type: 'warning' })return Promise.reject('error')} else if (code !== 200) {Notification.error({ title: msg })return Promise.reject('error')} else {if ( res.request.responseURL.indexOf('code') == -1 || res.config.method === 'post' || res.config.method=== 'put'  || res.config.method=== 'delete') {let decrypt = AES.decrypt(res.data);console.log(decrypt)return JSON.parse(decrypt)}return res.data}},error => {console.log('err' + error)let { message } = error;if (message == "Network Error") {message = "后端接口连接异常";} else if (message.includes("timeout")) {message = "系统接口请求超时";} else if (message.includes("Request failed with status code")) {message = "系统接口" + message.substr(message.length - 3) + "异常";}Message({ message: message, type: 'error', duration: 5 * 1000 })return Promise.reject(error)}
)// 通用下载方法
export function download(url, params, filename, config) {downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })return service.post(url, params, {transformRequest: [(params) => { return tansParams(params) }],headers: { 'Content-Type': 'application/x-www-form-urlencoded' },responseType: 'blob',...config}).then(async (data) => {const isBlob = blobValidate(data);if (isBlob) {const blob = new Blob([data])saveAs(blob, filename)} else {const resText = await data.text();const rspObj = JSON.parse(resText);const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']Message.error(errMsg);}downloadLoadingInstance.close();}).catch((r) => {console.error(r)Message.error('下载文件出现错误,请联系管理员!')downloadLoadingInstance.close();})
}export default service

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422385.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

51单片机-AT24C02(IIC总线介绍及其时序编写步骤)-第一节(下一节实战)

IIC开始通信&#xff08;6大步&#xff09; 我以前的文章也有对基本常用的通信协议讲解&#xff0c;如SPI UART IIC RS232 RS485 CAN的讲解&#xff0c;可前往主页查询&#xff0c;&#xff08;2024.9.12,晚上20&#xff1a;53&#xff0c;将AT24C02存储芯片&#xff0c;掉电不…

charles配置安卓抓包(避坑版)

1. 下载Charleshttps://www.charlesproxy.com/ 2. 安装&#xff0c;疯狂点击下一步即可 3. 注册&#xff1a;打开Charles&#xff0c;选择“Help”菜单中的“Register Charles”&#xff0c;进网站生成密钥&#xff1a;https://www.zzzmode.com/mytools/charles/,将生成的密钥…

【Linux修行路】信号的产生

目录 ⛳️推荐 一、信号的产生 二、产生信号的系统调用 2.1 kill——给指定的进程发送指定的信号 2.2 模拟实现指令 kill 2.3 raise——给调用的进程发送指定的信号 2.4 abort——给调用者发送 6 号信号 三、验证哪些信号不可以被捕捉 四、为什么除0和解引用空指针会给…

【C++】——vector

文章目录 vector介绍vector的使用vector的构造vector迭代器vector空间增减vector增删查改 vector介绍 vector是一个动态数组&#xff0c;可以根据需求变大变小vector支持随机访问vector会自动管理内存分配和释放vector在尾部添加和删除的效率非常高&#xff0c;中间和头部插入较…

Leetcode面试经典150题-134.加油站

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public int canCompleteCircuit(int[] gas, int[] cost) {/**如果只有一个加油站&#xff0c;那它本来就在那个为止&#xff0c;0就是它的编号?但是这只是你的想象&#xff0c;题目有个变态规定&#xff0c;自…

GD32/STM32启动过程

GD32/STM32启动过程 文章目录 GD32/STM32启动过程前言一、系统架构二、自举配置三、启动文件四、启动流程总结 前言 本文以STM32F407为例简单介绍其启动过程。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、系统架构 STM32F407的系统架构如图所…

DRW的公式推导及代码解析

流程 分阶段指定β值 # 根据当前epoch计算使用的beta值idx epoch // 160 # 每160轮epoch切换一次加权系数betas [0, 0.9999] # 两个beta值beta betas[idx] # 根据idx选择beta值 计算有效样本的权重 对权重进行归一化 &#xff08;每类权重值 / 权重总和&#xff09;* …

k8s--pod控制器--1

Pod控制器介绍 Pod是kubernetes的最小管理单元&#xff0c;在kubernetes中&#xff0c;按照pod的创建方式可以将其分为两类&#xff1a; 自主式pod&#xff1a;kubernetes直接创建出来的Pod&#xff0c;这种pod删除后就没有了&#xff0c;也不会重建 控制器创建的pod&#xf…

OpenStack × OceanBase: 打造高可用可扩展的基础设施平台

OceanBase 社区资深总监封仲淹在9月3日参加 OpenInfra 亚洲峰会中&#xff0c;分享了OceanBase与OpenStack的联合解决方案。本文将介绍这一联合方案的技术亮点及其为用户带来的独特价值。 OpenStack长期以来一直是云计算领域的先行者&#xff0c;通过提供强大的开源平台&#x…

前端正确设置资源上下文路径ContextPath(发布目录outDir 、公共基础路径),保证打包部署后站点能正常加载资源。

文章目录 引言I 处理资源上下文路径ContextPathjavascript对象获取上下文路径使用`./` 加载资源文件Vite 的basepublicPath是webpack部署应用包时的基本 URLII 知识扩展:URL的识别2.1 标准的链接格式2.2 URL中的?涵义2.3 URL中的&涵义2.4 传参III #fragment3.1为网页位置…

圆锥曲线练习

设 A ( x 1 , y 1 ) , B ( x 2 , y 2 ) A\left( x_{1}, y_{1} \right), B\left( x_{2}, y_{2} \right) A(x1​,y1​),B(x2​,y2​) l : y k ( x 2 ) l: y k\left( x2 \right) l:yk(x2) 显然 y 0 y0 y0符合题意 当 k ≠ 0 k\neq 0 k0 联立 l l l和 C C C ( k 2 1 2 ) x…

shader 案例学习笔记之偏移

效果 代码 #ifdef GL_ES precision mediump float; #endifuniform vec2 u_resolution; uniform float u_time;vec2 brickTile(vec2 _st, float _zoom){_st * 5.;_st.x step(1., mod(_st.y,2.0)) * 0.5;return fract(_st); }float box(vec2 _st, vec2 _size){_size vec2(0.5)…

【软考中级攻略站】-软件设计师(5)- 软件工程

软件生存周期 什么是软件生存周期&#xff1f; 软件生存周期指的是一个软件从开始构思到最终停止使用&#xff08;或被替换&#xff09;的整个过程。就像人的生命一样&#xff0c;软件也有一个从出生到死亡的过程。 软件生存周期的几个阶段 软件生存周期通常可以分为以下几…

DAY13信息打点-Web 应用源码泄漏开源闭源指纹识别GITSVNDS备份

#知识点 0、Web架构资产-平台指纹识别 1、开源-CMS指纹识别源码获取方式 2、闭源-习惯&配置&特性等获取方式 3、闭源-托管资产平台资源搜索监控 演示案例&#xff1a; ➢后端-开源-指纹识别-源码下载 ➢后端-闭源-配置不当-源码泄漏 ➢后端-方向-资源码云-源码泄漏 …

苹果宣布iOS 18正式版9月17日推送:支持27款iPhone升级

9月10日消息&#xff0c;在苹果秋季发布会结束后&#xff0c; 苹果宣布将于9月17日(下周二)推送iOS 18正式版系统。 苹果官网显示&#xff0c;iOS 18正式版将兼容第二代iPhone SE及之后的所有机型&#xff0c;加上刚发布的iPhone 16系列&#xff0c;共兼容27款iPhone。 iOS 18升…

算法学习攻略总结 : 入门至进阶,通关之路指南

❃博主首页 &#xff1a; <码到三十五> ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a; <搬的每块砖&#xff0c;皆为峰峦之基&#xff1b;公众号搜索(码到…

UE中如何制作后处理设置面板

1&#xff09;UE中如何制作后处理设置面板 2&#xff09;Magica Clothes 2插件与Burst编译问题 3&#xff09;UI大小和文本变量 4&#xff09;如何检索直线与网格的所有交点 这是第399篇UWA技术知识分享的推送&#xff0c;精选了UWA社区的热门话题&#xff0c;涵盖了UWA问答、社…

机械面试常见问题

文章目录 1.机械设计的一般思路&#xff08;方法&#xff09;2.公差等级有多少种3.机械传动的方式有哪些&#xff1f;选择的时候要考虑哪些问题&#xff1f;1. 齿轮传动2. 带传动3. 链传动4. 摩擦传动5. 螺旋传动6. 液压传动7. 气压传动8. 电磁传动总结 4.什么是宽禁带半导体&a…

4.1 符号定义伪指令

&#x1f393; 微机原理考点专栏&#xff08;通篇免费&#xff09; 欢迎来到我的微机原理专栏&#xff01;我将帮助你在最短时间内掌握微机原理的核心内容&#xff0c;为你的考研或期末考试保驾护航。 为什么选择我的视频&#xff1f; 全程考点讲解&#xff1a;每一节视频都…

【小沐学OpenGL】Ubuntu环境下glew的安装和使用

文章目录 1、简介1.1 OpenGL简介1.2 glew简介 2、安装glew2.1 命令安装glew2.2 直接代码安装glew2.3 cmake代码安装glew 3、测试glew3.1 测试glewfreeglut3.2 测试glewglfw 结语 1、简介 1.1 OpenGL简介 Linux 系统中的 OpenGL 是一个跨语言、跨平台的应用程序编程接口&#…