Vue、uniApp、微信小程序、Html5等实现数缓存

此文章带你实现前端缓存,利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具
不仅可以实现对缓存数据设置过期时间,还可以自定义是否需要对缓存数据进行加密处理

工具介绍说明

对缓存数据进行非对称加密处理
在这里插入图片描述
对必要数据进行缓存,并设置过期时间,并设置是否需要对缓存数据进行加密处理
在这里插入图片描述
其他工具
在这里插入图片描述

1、过期时间:封装好的工具,可以添加数据的缓存时长(过期时间)
2、是否加密:可以根据需求,是否需要对缓存的数据进行加密处理
3、加密解密:只需要简单配置,就可以实现缓存数据的加密解密功能
4、长期有效:对于不需要过期的数据,只要不手动清理可以长期有效
5、扩展性强:可以根据自己的需求直接进行代码的调整,简单易懂易扩展

本地缓存

1、VueHtml5 的数据缓存可以存放到localStoragecookie 或者 sessionStorage
2、uniApp、和 微信小程序 的数据缓存可以使用自带的API uni.setStorageSync

缓存的缺点

1、无论localStoragecookiesessionStorage 还是 uni.setStorageSync 都没有过期时间的限制
2、不能对数据进行实时的加解密处理,或者加解密扩展性差
3、对于大量旧的缓存数据还要手动处理,不能实时的去除旧数据

简单封装

代码以uniApp 为例,先实现可以添加过期时间的功能

缓存工具类:cacheUtil.js

const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './utils.js';

/**
 * 添加缓存
 * @param {String} key 缓存的key
 * @param {Object} val 缓存的val
 * @param {Number} expire 过期时间(单位:秒)
 * @returns {Boolean} 成功 | 失败
 */
export const setCache = (key, val, expire) => {
  if (isEmpty(key)) return false;
  expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;
  expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));
  let param = JSON.stringify({
    data: val, // 缓存的数据
    expire: expire // 过期时间
  });
  key = keyPrefix + key; // 缓存的key
  uni.setStorageSync(key, param); // 同步缓存
  return true;
}

/**
 * 获取缓存的数据
 * @param {String} key 缓存key
 * @returns {Object}
 */
export const getCache = (key) => {
  if (isEmpty(key)) return {};
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = value.expire || '';
    if (isEmpty(expire) || !isNumberStr(expire)) {
      return value.data || '';
    }
    expire = Number(expire) || 0;
    if (expire < Date.now()) {
      removeKeys(key);
      return {};
    }
  }
  return value.data;
}

/**
 * 获取缓存有效时长,单位:秒
 * @param {String} key 缓存的key
 * @param {Number} unit 0:毫秒,1:秒,2:分钟,默认毫秒值
 * @returns {Number} 有效时长
 */
export const getExpire = (key, unit) => {
  if (isEmpty(key)) return 0;
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = Number(value.expire || 0);
    if (unit === 1) return expire / 1000;
    if (unit === 2) return expire / 1000 / 60;
    return expire;
  }
  return 0;
}

/**
 * 给缓存设置过期时间
 * @param {String} key 缓存数据的key
 * @param {Number} expire 过期时长(单位:秒)
 */
export const setExpire = (key, expire) => {
  let value = getCache(key) || {};
  setCache(key, value, expire);
}

/**
 * 删除缓存数据
 * @param keys 删除缓存,多个key之间使用,隔开
 * @returns {Number} 删除条数
 */
export const removeKeys = (...keys) => {
  if (isEmpty(keys)) return 0;
  keys.forEach((key, index) => {
    key = keyPrefix + key;
    uni.removeStorageSync(key); // 同步删除
  });
  return keys.length;
}

/**
 * 清空所有缓存
 */
export const clearAll = () => {
  uni.clearStorageSync(); // 同步清除
}

数据加解密

我这里使用的使用非对称加密,根据个人项目需求可进行调整

加解密工具类:jsencryptUtil.js

import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const encryptor = new JSEncrypt();
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;

/**
 * 使用公钥进行加密处理
 * @param {string} txt 明文字符串
 */
export function encrypt(txt) {
  // 设置公钥
  encryptor.setPublicKey(publicKey); 
  // 对数据进行加密
  return encryptor.encrypt(txt); 
}

/**
 * 使用私钥进行解密处理
 * @param {string} enc 密文字符串
 */
export function decrypt(enc) {
  // 设置私钥
  encryptor.setPrivateKey(privateKey);
  // 对数据进行解密
  return encryptor.decrypt(enc); 
}

完善缓存工具

const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './utils.js';
import { encrypt, decrypt } from './jsencryptUtil.js';

/**
 * 添加缓存
 * @param {String} key 缓存的key
 * @param {Object} val 缓存的val
 * @param {Number} expire 过期时间(单位:秒)
 * @param {Boolean} enc 是否需要加密处理:true | false
 * @returns {Boolean} 成功 | 失败
 */
export const setCache = (key, val, expire, enc) => {
  if (isEmpty(key)) return false;
  expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;
  expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));
  let param = JSON.stringify({
    data: val, // 缓存的数据
    expire: expire // 过期时间
  });
  if (enc === true) param = encrypt(param );
  key = keyPrefix + key; // 缓存的key
  uni.setStorageSync(key, param); // 同步缓存
  return true;
}

/**
 * 获取缓存的数据
 * @param {String} key 缓存key
 * @param {Boolean} dec 是否需要解密处理:true | false
 * @returns {Object}
 */
export const getCache = (key, dec) => {
  if (isEmpty(key)) return {};
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (dec === true) value = decrypt(value);
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = value.expire || '';
    if (isEmpty(expire) || !isNumberStr(expire)) {
      return value.data || '';
    }
    expire = Number(expire) || 0;
    if (expire < Date.now()) {
      removeKeys(key);
      return {};
    }
  }
  return value.data;
}

/**
 * 删除缓存数据
 * @param keys 删除缓存,多个key之间使用,隔开
 * @returns {Number} 删除条数
 */
export const removeKeys = (...keys) => {
  if (isEmpty(keys)) return 0;
  keys.forEach((key, index) => {
    key = keyPrefix + key;
    uni.removeStorageSync(key); // 同步删除
  });
  return keys.length;
}

/**
 * 清空所有缓存
 */
export const clearAll = () => {
  uni.clearStorageSync(); // 同步清除
}

这样就可以对缓存的数据进行加密处理了

每次都要传入一个参数来确定是否需要加密或者解密处理,太繁琐了
能不能不需要我来传是否需要解密呢?根据加密参数进行判断?答案时可以的

接下来,我们先处理一下加解密工具,对于很长很长的明文数据进行加密时,加密工具会报错
下面对加密工具进行改造,改造完成之后,再来进一步完善缓存工具,不用每次都传入解密标志

加密太长报错

使用 JSEncrypt 加密数据时,对于比较长的字符串,加密时会出现异常报错,并提示数据太大

解决方法:需要对加密工具进行一次改造处理

修改加密工具

import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const encryptor = new JSEncrypt();
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;

/**
 * 使用公钥进行加密处理
 * @param {string} txt 明文字符串
 */
export function encrypt(txt) {
  encryptor.setPublicKey(publicKey); // 设置公钥
  if (txt.length > 100) {
    let result = "";
    while (txt && txt.length > 0) {
      let dl = txt.slice(0, 100);
      txt = txt.slice(100);
      if (!result) {
        result = result + encryptor.encrypt(dl);
      } else {
        result = result + "~" + encryptor.encrypt(dl);
      }
    }
    return result;
  }
  return encryptor.encrypt(txt); // 对数据进行加密
}

/**
 * 使用私钥进行解密处理
 * @param {string} enc 密文字符串
 */
export function decrypt(enc) {
  // 设置私钥
  encryptor.setPrivateKey(privateKey);
  if (enc.includes("~")) {
    let result = "";
    let arr = enc.split("~");
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] && arr[i].length > 0) {
        result = result + encryptor.decrypt(arr[i]);
      }
    }
    return result;
  }
  return encryptor.decrypt(enc);
}

改造缓存工具

const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './util.js';
import { encrypt, decrypt } from './jsencryptUtil.js';

/**
 * 添加缓存
 * @param {String} key 缓存的key
 * @param {Object} val 缓存的val
 * @param {Number} expire 过期时间(单位:秒)
 * @param {Boolean} enc 是否需要加密处理:true | false
 * @returns {Boolean} 成功 | 失败
 */
export const setCache = (key, val, expire, enc) => {
  if (isEmpty(key)) return false;
  expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;
  expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));
  enc = enc === true;
  let param = JSON.stringify({
    data: (enc ? encrypt(val) : val), // 缓存的数据
    encrypt: enc, // 数据加密标志
    expire: expire // 过期时间
  });
  key = keyPrefix + key; // 缓存的key
  uni.setStorageSync(key, param); // 同步缓存
  return true;
}

/**
 * 获取缓存的数据
 * @param {String} key 缓存key
 * @returns {Object}
 */
export const getCache = (key) => {
  if (isEmpty(key)) return {};
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = value.expire || '';
    let dec = value.encrypt == true;
    if (dec) value.data = decrypt(value.data);
    if (isEmpty(expire) || !isNumberStr(expire)) {
      return value.data || '';
    }
    expire = Number(expire) || 0;
    if (expire < Date.now()) {
      removeKeys(key);
      return {};
    }
  }
  return value;
}

/**
 * 删除缓存数据
 * @param keys 删除缓存,多个key之间使用,隔开
 * @returns {Number} 删除条数
 */
export const removeKeys = (...keys) => {
  if (isEmpty(keys)) return 0;
  keys.forEach((key, index) => {
    key = keyPrefix + key;
    uni.removeStorageSync(key); // 同步删除
  });
  return keys.length;
}

/**
 * 清空所有缓存
 */
export const clearAll = () => {
  uni.clearStorageSync(); // 同步清除
}

到此,缓存工具就完成了,只要在缓存时传入是否需要加密的参数就可以了,解密时只需要传入key就可以了,不需要再额外传入解密参数

最终完整代码

util工具

util.js

/**
 * 判断数据是否为空
 * @param {*} input 原数据
 * @return {Boolean}
 */
export const isEmpty = (input) => {
  if (Object.prototype.toString.call(input) === '[object Object]') {
    let vals = Object.values(input) || [];
    let num = 0;
    for (let val of vals) {
      val = (!val ? '' : JSON.stringify(val)).trim().replace(/\s*/g, "");
      num = !val ? num + 1 : num;
    }
    return vals.length === num;
  }
  if (typeof input !== 'string') input = (!input ? '' : JSON.stringify(input)).trim().replace(/\s*/g, "");
  return !input || input.length === 0 || (['[]', '{}', 'NaN', 'null', 'undefined'].includes(input));
}

/**
 * 去除特殊字符,包括但不限于空格、制表符\t、换行符\r、回车符\n
 * @param {string} input 原数据
 * @return {string}
 */
export const trimAllBlank = (input) => {
  input = typeof input === 'string' ? input.trim() : JSON.stringify(input);
  return (input || '').replace(/\s*/g, "");
}

/**
 * 是否数字
 * @param {string} str 字符串
 * @returns {boolean}
 */
export const isNumberStr = (str) => {
  str = isEmpty(str) ? '' : str;
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}

加密工具

jsencryptUtil.js

import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;

/**
 * 使用公钥进行加密处理
 * @param {string} txt 明文字符串
 */
export function encrypt(txt) {
  const encryptor = new JSEncrypt();
  encryptor.setPublicKey(publicKey); // 设置公钥
  if (txt.length > 100) {
    let result = "";
    while (txt && txt.length > 0) {
      let dl = txt.slice(0, 100);
      txt = txt.slice(100);
      if (!result) {
        result = result + encryptor.encrypt(dl);
      } else {
        result = result + "~" + encryptor.encrypt(dl);
      }
    }
    return result;
  }
  return encryptor.encrypt(txt); // 对数据进行加密
}

/**
 * 使用私钥进行解密处理
 * @param {string} enc 密文字符串
 */
export function decrypt(enc) {
  const encryptor = new JSEncrypt();
  encryptor.setPrivateKey(privateKey);
  if (enc.includes("~")) {
    let result = "";
    let arr = enc.split("~");
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] && arr[i].length > 0) {
        result = result + encryptor.decrypt(arr[i]);
      }
    }
    return result;
  }
  return encryptor.decrypt(enc);
}

缓存工具

cacheUtil.js

const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './util.js';
import { encrypt, decrypt } from './jsencryptUtil.js';

/**
 * 添加缓存
 * @param {String} key 缓存的key
 * @param {Object} val 缓存的val
 * @param {Number} expire 过期时间(单位:秒)
 * @param {Boolean} enc 是否需要加密处理:true | false
 * @returns {Boolean} 成功 | 失败
 */
export const setCache = (key, val, expire, enc) => {
  if (isEmpty(key)) return false;
  expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;
  expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));
  enc = enc === true;
  let param = JSON.stringify({
    data: (enc ? encrypt(val) : val), // 缓存的数据
    encrypt: enc, // 数据加密标志
    expire: expire // 过期时间
  });
  key = keyPrefix + key; // 缓存的key
  uni.setStorageSync(key, param); // 同步缓存
  return true;
}

/**
 * 获取缓存的数据
 * @param {String} key 缓存key
 * @returns {Object}
 */
export const getCache = (key) => {
  if (isEmpty(key)) return {};
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = value.expire || '';
    let dec = value.encrypt == true;
    if (dec) value.data = decrypt(value.data);
    if (isEmpty(expire) || !isNumberStr(expire)) {
      return value.data || '';
    }
    expire = Number(expire) || 0;
    if (expire < Date.now()) {
      removeKeys(key);
      return {};
    }
  }
  return value;
}

/**
 * 获取缓存有效时长,单位:秒
 * @param {String} key 缓存的key
 * @param {Number} unit ms:毫秒,s:秒,m:分钟,默认毫秒值
 * @returns {Number} 有效时长
 */
export const getExpire = (key, unit) => {
  if (isEmpty(key)) return 0;
  key = keyPrefix + key;
  let value = uni.getStorageSync(key) || '';
  if (value.includes('data') && value.includes('expire')) {
    value = JSON.parse(value) || {};
    let expire = Number(value.expire || 0);
    unit = unit.toLowerCase();
    if (unit === "s") return expire / 1000;
    if (unit === "m") return expire / 1000 / 60;
    return expire;
  }
  return 0;
}

/**
 * 给缓存设置过期时间
 * @param {String} key 缓存数据的key
 * @param {Number} expire 过期时长(单位:秒)
 */
export const setExpire = (key, expire) => {
  let value = getCache(key) || {};
  setCache(key, value, expire);
}

/**
 * 删除缓存数据
 * @param keys 删除缓存,多个key之间使用,隔开
 * @returns {Number} 删除条数
 */
export const removeKeys = (...keys) => {
  if (isEmpty(keys)) return 0;
  keys.forEach((key, index) => {
    key = keyPrefix + key;
    uni.removeStorageSync(key); // 同步删除
  });
  return keys.length;
}

/**
 * 清空所有缓存
 */
export const clearAll = () => {
  uni.clearStorageSync(); // 同步清除
}

其他语言改造

vue:vue中使用时,需要将 uni.xxxStorage(...) 替换为localStorage 或者 sessionStorage
html5:和 vue 一样,需要将 uni.xxxStorage(...) 替换为localStorage 或者 sessionStorage
微信小程序:需要将 uni.xxxStorage(...) 替换为 wx.xxxStorage(...)

localStorage和sessionStorage的区别:
sessionStorage:只在本次会话有效,关闭浏览器数据将被删除
localStorage:如果不手动删除,则长期有效,关闭浏览器数据也不会被清除

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

太平洋产险海南分公司:春季爱车保养,就看这几点!

一年之计在于春&#xff0c;春天不仅是万物复苏的好时节&#xff0c;也是一年中非常适合汽车养护的季节。 刚刚过去的春节&#xff0c;汽车的使用频率大大增加&#xff0c;很多车主都准备对爱车进行一次全面保养。加上立春过后&#xff0c;天气渐暖&#xff0c;许多车主也计划开…

答题小程序源码系统:自带流量主广告位+视频激励广告 带完整的代码安装包以及搭建教程

随着互联网的迅速发展&#xff0c;各种应用程序层出不穷&#xff0c;而答题类小程序由于其独特的互动性和吸引力&#xff0c;成为了当前最热门的应用之一。答题小程序源码系统是一款基于微信小程序开发的源代码系统&#xff0c;它具有丰富的功能和灵活的定制性&#xff0c;可以…

搭建算法日志自检小系统

&#x1f952; 前言 目前演示的是一个工具&#xff0c;但如此&#xff0c;未来完成有潜力可以演变为一整套系统。 &#x1f451;现场人员自检失败表计点位教程V2.0 NOTE: 如果没有“logfiles-meter-tool“目录的请联系我们进行提供&#xff01; &#x1f447; 进入<dist>…

使用AutoDL云计算平台训练并测试Pytorch版本NeRF代码

文章目录 前言一、数据集及代码获取二、租用并设置服务器三、Pycharm远程开发四、训练并测试代码 前言 因为第一次在云服务器上跑代码&#xff0c;所以在这里记录一下。 一、数据集及代码获取 nerf-pytorch项目是 NeRF 的忠实 PyTorch 实现&#xff0c;它在运行速度提高 1.3 倍…

docker 利用特权模式逃逸并拿下主机

docker 利用特权模式逃逸并拿下主机 在溯源反制过程中&#xff0c;会经常遇到一些有趣的玩法&#xff0c;这里给大家分享一种docker在特权模式下逃逸&#xff0c;并拿下主机权限的玩法。 前言 在一次溯源反制过程中&#xff0c;发现了一个主机&#xff0c;经过资产收集之后&…

SSL证书与HTTPS的关系

SSL证书是一种数字证书&#xff0c;由权威的证书颁发机构颁发。它包含了一个公钥和有关证书所有者的一些信息&#xff0c;如名称、组织、邮箱等。SSL证书的主要作用是实现数据加密和身份验证&#xff0c;确保数据在传输过程中的安全性和完整性。 HTTPS是一种基于HTTP协议的安全…

Web开发:SQLsugar的安装和使用

一、安装 第一步&#xff0c;在你的项目中找到解决方案&#xff0c;右键-管理解决方案的Nuget 第二步&#xff0c;下载对应的包&#xff0c;注意你的框架是哪个就下载哪个的包&#xff0c;一个项目安装一次包即可 点击应用和确定 安装好后会显示sqlsugar的包 二、使用&#xf…

UOS Python+Qt5实现声卡回路测试

1.回路治具设计&#xff1a; 2.Ui界面&#xff1a; 3.源代码&#xff1a; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file SoundTestWinFrm.ui # # Created by: PyQt5 UI code generator 5.15.2 # # WARNING: Any manual changes made to this…

3d云渲染用什么显卡比较好?3d云渲染显卡推荐

3D云渲染能加快渲染速度&#xff0c;是众多公司的首选方案&#xff0c;作为公司负责人&#xff0c;选择哪个平台值得思考&#xff0c;今天我就说下我的选择吧。 首先我们要了解云渲染的渲染方式&#xff0c;云渲染的渲染方式分两种&#xff0c;一种是CPU渲染&#xff0c;一种是…

C++程序员必备的面试技巧

“程序员必备的面试技巧&#xff0c;就像是编写一段完美的代码一样重要。在面试战场上&#xff0c;我们需要像忍者一样灵活&#xff0c;像侦探一样聪明&#xff0c;还要像无敌铁金刚一样坚定。只有掌握了这些技巧&#xff0c;我们才能在面试的舞台上闪耀光芒&#xff0c;成为那…

Windows 远程控制之 PsExec

1、介绍&#xff1a; PsExec 是一种轻量级 telnet 替代品&#xff0c;可让你在其他系统上执行进程&#xff0c;并为控制台应用程序提供完整交互性&#xff0c;而无需手动安装客户端软件。 PsExec 最强大的用途包括在远程系统上启动交互式命令提示符&#xff0c;以及 IpConfig …

【LeetCode】2619. 数组原型对象的最后一个元素

数组原型对象的最后一个元素 题目题解 题目 请你编写一段代码实现一个数组方法&#xff0c;使任何数组都可以调用 array.last() 方法&#xff0c;这个方法将返回数组最后一个元素。如果数组中没有元素&#xff0c;则返回 -1。 你可以假设数组是 JSON.parse 的输出结果。 示例 …

Postgres 中文周报:Postgres Weekly 537 期

本周报由 Cloudberry Database 社区编译自英文版《Postgres Weekly》&#xff0c;译文较原文有所调整。 推荐博文 &#x1f3c6; PostgreSQL: The DBMS of the Year 2023 PostgreSQL 荣获 DB-Engines 网站 2023 年度 DBMS 冠军。DB-Engines 收集了 480 款数据库系统信息并跟踪…

JAVA循环结构

目录 if语句 1、if语句第一种格式 2、if的第二种格式 3、if的第三种格式 switch语句 1、switch格式 2、switch练习 3、switch规则 循环 1、格式 2、练习 if语句 1、if语句第一种格式 package 分支结构;import java.util.Scanner;public class ifjiegou {public sta…

C Primer Plus 第6版 编程练习 chapter 13

文章目录 1. 第1题1.1 题目描述1.2 编程源码1.3 结果显示 2. 第2题2.1 题目描述2.2 编程源码2.3 结果显示 3. 第3题3.1 题目描述3.2 编程源码3.3 结果显示 4. 第4题4.1 题目描述4.2 编程源码4.3 结果显示 5. 第5题5.1 题目描述5.2 编程源码5.3 结果显示 6. 第6题6.1 题目描述6.…

​水经微图Web1.5.0版即将上线

让每一个人都有自己的地图&#xff01; 最近我们上线了水经微图&#xff08;简称“微图”&#xff09;Web1.4.0版&#xff0c;现在1.5.0版也即将上线&#xff0c;接下来的1.6.0版研发计划也已经确定好。 这里就来分享一下已上线的版本&#xff0c;即将上线的版本&#xff0c;…

virtualbox Ubuntu 网络连接

一、网络连接需求1—— 上网&#xff1a; 虚拟机默认的NAT连接方式&#xff0c;几乎不需要怎么配置&#xff0c;即可实现上网。 enp0s17以太网必须要开启&#xff0c;才能上网&#xff1b; 但是主机ping不通虚拟机&#xff0c;貌似可以ping 127.0.0.1; 二、主机和虚拟机相互p…

8年经验之谈!一文看懂性能测试的流程!

每天做着点点点测试有没有危机感&#xff1f; 突然有一天&#xff0c;领导说&#xff1a;“小王&#xff0c;今天把996福报系统压一下&#xff0c;下班前把压测报告发我邮箱。” 啥&#xff1f;压测&#xff1f;今天&#xff1f;报告&#xff1f;怎么压&#xff1f;怎么写&am…

java多线程面试集合(1)

1.并行和并发的区别 操作系统角度&#xff0c;线程是最小的执行单位 并行同一时刻两个线程都在执行&#xff0c;这就要求要有两个cpu。并发就是 同一时刻&#xff0c;只有一个执行但是在一个时间段内&#xff0c;两个线程都执行了&#xff0c;并发依赖于CPU切换线程&#xff…