我的编程空间,编程开发者的网络收藏夹
学习永远不晚

go GCM gin中间件的加密解密文件流处理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

go GCM gin中间件的加密解密文件流处理

aes的gcm模式的加密和解密

要给已有的系统启用加密解密,目前推荐的是aes的gcm模式的加密和解密,在微服务如果向前有公共方法处理 读取数据和写返回数据,那么比较简单,修改以前的公共方法,但是这样本地调试平时肯定是明文,所以要加判断,如果以前的读数据和写数据是五花八门那就比较麻烦,在微服务体系里面一般有网关这个服务,所以加密和解密就放在网关服务,大致如下:

常规的请求有GET,POST JSON, POST file,以及POST Form表单,返回一般是json 或者下载文件流,所以我们需要截获请求流和返回流,收到请求流解密数据 然后重新写入到请求流,收到返回流加密数据,重写返回流。

首先来看aes加密和解密程序aes.go

package aes
import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"io"
)
//加密字符串
func GcmEncrypt(key, plaintext string) (string, error) {
	if len(key) != 32 && len(key) != 24 && len(key) != 16 {
		return "", errors.New("the length of key is error")
	}
	if len(plaintext) < 1 {
		return "", errors.New("plaintext is null")
	}
	keyByte := []byte(key)
	plainByte:=[]byte(plaintext)
	block, err := aes.NewCipher(keyByte)
	if err != nil {
		return "", err
	}
	aesGcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}
	nonce := make([]byte, 12)
	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}
	seal := aesGcm.Seal(nonce, nonce, plainByte, nil)
	return base64.URLEncoding.EncodeToString(seal), nil
}
//解密字符串
func GcmDecrypt(key, cipherText string) (string, error) {
	if len(key) != 32 && len(key) != 24 && len(key) != 16 {
		return "", errors.New("the length of key is error")
	}
	if len(cipherText) < 1 {
		return "", errors.New("cipherText is null")
	}
	cipherByte, err := base64.URLEncoding.DecodeString(cipherText)
	if err != nil {
		return "", err
	}
	if len(cipherByte) < 12 {
		return "", errors.New("cipherByte is error")
	}
	nonce, cipherByte := cipherByte[:12], cipherByte[12:]
	keyByte := []byte(key)
	block, err := aes.NewCipher(keyByte)
	if err != nil {
		return "", err
	}
	aesGcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}
	plainByte, err := aesGcm.Open(nil, nonce, cipherByte, nil)
	if err != nil {
		return "", err
	}
	return string(plainByte), nil
}
//生成32位md5字串
func GetAesKey(s string) string {
		h := md5.New()
		h.Write([]byte(s))
		return hex.EncodeToString(h.Sum(nil))
}

再来看看网关转发程序proxy.go

package middleware
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/valyala/fasthttp"
	"io/ioutil"
	"runtime/debug"
	"time"
)
var fastClient *fasthttp.Client
func init() {
	fastClient = &fasthttp.Client{}
	fastClient.MaxIdemponentCallAttempts = 1
	fastClient.ReadTimeout = time.Second * 60
}
func GetHttpClient() *fasthttp.Client {
	return fastClient
}
func GateWay() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if e := recover(); e != nil {
				stack := debug.Stack()
				log("GateWay Recovery: err:%v, stack:%v", e, string(stack))
			}
		}()
		err := Forward(c)
		if err != nil {
			response(c, 9999, "系统错误", err.Error())
		}
		return
	}
}
func Forward(ctx *gin.Context) error {
	req := &fasthttp.Request{}
	//请求-获取服务地址
	host := "http://localhost:8000/" + ctx.Request.URL.String()
	//请求-url
	req.SetRequestURI(host)
	//请求-header
	for k, v := range ctx.Request.Header {
		req.Header.Set(k, v[0])
	}
	//请求-body
	data, err := ioutil.ReadAll(ctx.Request.Body)
	if err != nil {
		log("Forward err:%v", err)
		return fmt.Errorf("系统错误")
	}
	req.SetBody(data)
	//请求-方法
	req.Header.SetMethod(ctx.Request.Method)
	//请求-发送
	resp := &fasthttp.Response{}
	//请求-新增调用链
	
	err = GetHttpClient().Do(req, resp)
	if err != nil {
		log("Forward GetHttpClient DO err:%v", err)
		return fmt.Errorf("系统错误")
	}
	//请求-响应
	ContentType := fmt.Sprintf("%s", resp.Header.Peek("Content-Type"))
	ctx.Data(resp.StatusCode(), ContentType, resp.Body())
	return nil
}
type HTTPHeadersCarrier struct {
	*fasthttp.RequestHeader
}
func (c HTTPHeadersCarrier) Set(key, val string) {
	h := c.RequestHeader
	h.Add(key, val)
}

最后来看一下gin的中间件crypto.go

package middleware
import (
	"bytes"
	"demo/aes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"io"
	"io/ioutil"
	"mime"
	"mime/multipart"
	"net/url"
	"runtime/debug"
	"strconv"
	"strings"
)
type aesWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}
func (w *aesWriter) Write(b []byte) (int, error) {
	return w.body.Write(b)
}
func (w *aesWriter) WriteString(s string) (int, error) {
	return w.body.WriteString(s)
}
//只有经过token 验证的才会加密 和解密
//handleFile 表示是否处理上传文件, 默认网关不处理上传文件的encryptString数据, 如果处理会导致具体服务无法接收到具体参数
func AesGcmDecrypt() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			if e := recover(); e != nil {
				stack := debug.Stack()
				log("AesGcmDecrypt Recovery: err:%v, stack:%v", e, string(stack))
			}
		}()
		if c.Request.Method == "OPTIONS" {
			c.Next()
		} else {
			md5key := aes.GetAesKey("gavin12345678")
			log("AesGcmDecrypt start url:%s  ,md5key:%s, Method:%s, Header:%+v", c.Request.URL.String(), md5key, c.Request.Method, c.Request.Header)
			handleAes(c, md5key)
		}
	}
}
//请求和返回都加密 解密
func handleAes(c *gin.Context, md5key string) {
	contentType := c.Request.Header.Get("Content-Type")
	isJsonRequest := strings.Contains(contentType, "application/json")
	isFileRequest := strings.Contains(contentType, "multipart/form-data")
	isFormUrl := strings.Contains(contentType, "application/x-www-form-urlencoded")
	if c.Request.Method == "GET" {
		err := parseQuery(c, md5key)
		if err != nil {
			log("handleAes parseQuery  err:%v", err)
			//这里输出应该密文 一旦加密解密调试好 这里就不会走进来
			response(c, 2001, "系统错误", err.Error())
			return
		}
	} else if isJsonRequest {
		err := parseJson(c, md5key)
		if err != nil {
			log("handleAes parseJson err:%v", err)
			//这里输出应该密文 一旦加密解密调试好 这里就不会走进来
			response(c, 2001, "系统错误", err.Error())
			return
		}
	} else if isFormUrl {
		err := parseForm(c, md5key)
		if err != nil {
			log("handleAes parseForm err:%v", err)
			//这里输出应该密文 一旦加密解密调试好 这里就不会走进来
			response(c, 2001, "系统错误", err.Error())
			return
		}
	} else if isFileRequest {
		err := parseFile(c, md5key)
		if err != nil {
			log("handleAes parseFile err:%v", err)
			//这里输出应该密文 一旦加密解密调试好 这里就不会走进来
			response(c, 2001, "系统错误", err.Error())
			return
		}
	}
	///截取 response body
	oldWriter := c.Writer
	blw := &aesWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
	c.Writer = blw
	// 走流程
	c.Next()
	///获取返回数据
	responseByte := blw.body.Bytes()
	//日志
	c.Writer = oldWriter
	//如果返回的不是json格式 那么直接返回,应为文件下载之类的不应该加密
	if !isJsonResponse(c) {
		_, _ = c.Writer.Write(responseByte)
		return
	}
	///加密
	encryptStr, err := aes.GcmEncrypt(md5key, string(responseByte))
	if err != nil {
		log("handleAes GcmEncrypt err:%v", err)
		response(c, 2001, "系统错误", err.Error())
		return
	}
	_, _ = c.Writer.WriteString(encryptStr)
}
//处理json
func parseJson(c *gin.Context, md5key string) error {
	//读取数据 body处理
	payload, err := c.GetRawData()
	if err != nil {
		return err
	}
	///解密body数据 请求的json是{"encryptString":{value}} value含有gcm的12字节nonce,实际长度大于32
	if payload != nil && len(payload) > 20 {
		var jsonData encryptJson
		log("AesGcmDecrypt  parseJson url:%s md5key:%s,old data:%s,", c.Request.URL.String(), md5key, string(payload))
		err := json.Unmarshal(payload, &jsonData)
		if err != nil {
			log("AesGcmDecrypt parseJson Unmarshal err:%v", err)
			return err
		}
		payloadText := jsonData.EncryptString
		if len(payloadText) > 0 {
			payloadText, err = aes.GcmDecrypt(md5key, payloadText)
			if err != nil {
				log("AesGcmDecrypt parseJson GcmDecryptByte err:%v", err)
				return err
			}
			payload = []byte(payloadText)
			log("AesGcmDecrypt  parseJson url:%s md5key:%s,encryptString:%s,decrypt data:%s", c.Request.URL.String(), md5key, jsonData.EncryptString, payloadText)
		}
	}
	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(payload))
	return nil
}
func parseForm(c *gin.Context, md5key string) error {
	//读取数据 body处理
	payload, err := c.GetRawData()
	if err != nil {
		return err
	}
	///解密body数据 请求的json是"encryptString= value含有gcm的12字节nonce,实际长度大于32
	if payload != nil && len(payload) > 20 {
		var jsonData encryptJson
		log("AesGcmDecrypt  parseForm url:%s md5key:%s,old data:%s,", c.Request.URL.String(), md5key, string(payload))
		values, err := url.ParseQuery(string(payload))
		if err != nil {
			log("AesGcmDecrypt parseForm ParseQuery err:%v", err)
			return err
		}
		payloadText := values.Get("encryptString")
		if len(payloadText) > 0 {
			mapData, err := gcmDecryptString(md5key, payloadText)
			if err != nil {
				log("AesGcmDecrypt parseForm gcmDecryptString err:%v", err)
				return err
			}
			for k, v := range mapData {
				values.Add(k, getStr(v))
			}
			formData := values.Encode()
			log("AesGcmDecrypt  parseForm url:%s md5key:%s,encryptString:%s,decrypt data:%s", c.Request.URL.String(), md5key, jsonData.EncryptString, formData)
			payload = []byte(formData)
		}
	}
	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(payload))
	return nil
}
//处理get url的解密
func parseQuery(c *gin.Context, md5Key string) error {
	encryptString := c.Query("encryptString")
	log("AesGcmDecrypt parseQuery url:%s, md5key:%s, encryptString:%s", c.Request.URL.String(), md5Key, encryptString)
	if len(encryptString) < 1 {
		return nil
	}
	queryData, err := gcmDecryptString(md5Key, encryptString)
	if err != nil {
		return err
	}
	var args []string
	var logs []string
	for k, v := range queryData {
		val := getStr(v)
		args = append(args, fmt.Sprintf("%s=%s", k, url.QueryEscape(val)))
		logs = append(logs, fmt.Sprintf("%s=%s", k, val))
	}
	log("AesGcmDecrypt parseQuery  url:%s, md5key:%s, encryptString:%s, decrypt data:%s", c.Request.URL.String(), md5Key, encryptString, strings.Join(logs, "&"))
	c.Request.URL.RawQuery = strings.Join(args, "&")
	return nil
}
func parseFile(c *gin.Context, md5Key string) error {
	contentType := c.Request.Header.Get("Content-Type")
	_, params, _ := mime.ParseMediaType(contentType)
	boundary, ok := params["boundary"]
	if !ok {
		return errors.New("no multipart boundary param in Content-Type")
	}
	//准备重写数据
	bodyBuf := &bytes.Buffer{}
	wr := multipart.NewWriter(bodyBuf)
	mr := multipart.NewReader(c.Request.Body, boundary)
	for {
		p, err := mr.NextPart() //p的类型为Part
		if err == io.EOF {
			break
		}
		if err != nil {
			log("NextPart err:%v", err)
			break
		}
		fileByte, err := ioutil.ReadAll(p)
		if err != nil {
			log("ReadAll err:%v", err)
			break
		}
		pName := p.FormName()
		fileName := p.FileName()
		if len(fileName) < 1 {
			if pName == "encryptString" {
				formData, err := gcmDecryptString(md5Key, string(fileByte))
				if err != nil {
					log("AesGcmDecrypt writeFile gcmDecryptString err:%v", err)
					break
				}
				for k, v := range formData {
					val := getStr(v)
					err = wr.WriteField(k, val)
					if err != nil {
						log("AesGcmDecrypt writeFile WriteField :%s=%s, err:%v", k, val, err)
						break
					}
				}
			} else {
				wr.WriteField(pName, string(fileByte))
			}
		} else {
			tmp, err := wr.CreateFormFile(pName, fileName)
			if err != nil {
				log("AesGcmDecrypt parseFile CreateFormFile err:%v", err)
				continue
			}
			tmp.Write(fileByte)
		}
	}
	//写结尾标志
	_ = wr.Close()
	c.Request.Header.Set("Content-Type", wr.FormDataContentType())
	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBuf.Bytes()))
	return nil
}
func gcmDecryptString(md5Key, encryptString string) (map[string]interface{}, error) {
	formData := make(map[string]interface{}, 0)
	if len(encryptString) < 1 {
		return formData, nil
	}
	plaintext, err := aes.GcmDecrypt(md5Key, encryptString)
	if err != nil {
		return formData, err
	}
	if len(plaintext) < 3 {
		//plaintext 应该是json 串 {}
		return formData, nil
	}
	err = json.Unmarshal([]byte(plaintext), &formData)
	if err != nil {
		return formData, err
	}
	return formData, nil
}
func isJsonResponse(c *gin.Context) bool {
	contentType := c.Writer.Header().Get("Content-Type")
	return strings.Contains(contentType, "application/json")
}
func getStr(v interface{}) string {
	val := ""
	switch v.(type) {
	case float64:
		//tmp, _ := decimal.NewFromString(fmt.Sprintf("%.10f", v))
		fl, _ := v.(float64)
		val = strconv.FormatFloat(fl, 'f', -1, 64)
	default:
		val = fmt.Sprintf("%v", v)
	}
	return val
}
type encryptJson struct {
	EncryptString string `json:"encryptString"`
}
func log(format string, arg ...interface{}) {
	fmt.Print(fmt.Sprintf(format, arg...))
}
func response(c *gin.Context, code int, msg string, data interface{}) {
	mapData := make(map[string]interface{}, 0)
	mapData["code"] = code
	mapData["msg"] = msg
	mapData["data"] = data
	c.JSON(200, data)
	c.Abort()
	return
}

最后我们来写一个demo程序main.go

package main
import (
	"demo/middleware"
	"fmt"
	"github.com/gin-gonic/gin"
	"os"
)
func main() {
	go func() {
		gateway := gin.Default()
		gateway.Use(middleware.AesGcmDecrypt())
		gateway.Use(middleware.GateWay())
		gateway.Run(":8080")
	}()
	// 1.创建路由
	r := gin.Default()
	r.Use(middleware.Logger())
	r.GET("/", func(c *gin.Context) {
		c.Writer.WriteString("pong")
	})
	r.GET("/demo", func(c *gin.Context) {
		req := ReqObj{}
		err := c.ShouldBindQuery(&req)
		if err != nil {
			fmt.Print(err)
		}
		response(c, 200, "ok", req)
	})
	r.POST("/test", func(c *gin.Context) {
		req := ReqObj{}
		err := c.ShouldBind(&req)
		if err != nil {
			fmt.Print(err)
		}
		response(c, 200, "ok", req)
	})
	r.POST("/form", func(c *gin.Context) {
		req := ReqObj{}
		err := c.ShouldBind(&req)
		if err != nil {
			fmt.Print(err)
		}
		response(c, 200, "ok", req)
	})
	r.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("file")
		if err != nil {
			fmt.Print(err)
		}
		folder := c.Request.FormValue("folder")
		tmp, _ := os.Getwd()
		filePath := tmp + "/upload/" + folder + "/" + file.Filename
		c.SaveUploadedFile(file, filePath)
	})
	r.Run(":8000")
}
type ReqObj struct {
	Name       string `json:"name" form:"name"`
	Age        int64  `json:"age"  form:"age"`
	UpdateTime int64  `json:"update_time"  form:"update_time"`
	Folder     string `json:"folder"  form:"folder"`
}
func response(c *gin.Context, code int, msg string, data interface{}) {
	mapData := make(map[string]interface{}, 0)
	mapData["code"] = code
	mapData["msg"] = msg
	mapData["data"] = data
	c.JSON(200, data)
	c.Abort()
	return
}

验证

来让我们一次验证一下运行结果:

1.GET请求

2.看看post json

3验证postform

最后来看一下文件上传:

下载地址 :https://github.com/dz45693/gindemo

以上就是go GCM gin中间件的加密解密文件流处理的详细内容,更多关于go GCM gin加密解密文件流的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

go GCM gin中间件的加密解密文件流处理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

go GCM gin中间件怎么加密解密文件

这篇文章主要介绍“go GCM gin中间件怎么加密解密文件”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“go GCM gin中间件怎么加密解密文件”文章能帮助大家解决问题。aes的gcm模式的加密
2023-06-30

如何处理Go语言中的并发文件的加密和解密问题?

如何处理Go语言中的并发文件的加密和解密问题?引言:随着互联网的发展和信息传输的普及,文件加密和解密已经成为保护数据安全的重要手段。而且,随着计算机处理能力和存储容量的提升,同时处理多个文件的需求也日益增加。在Go语言中,我们可以利用并发的
2023-10-22

android中对文件加密解密的实现

现在项目里面有一个需求,本项目里面下载的视频和文档都不允许通过其他的播放器播放,在培训机构里面这样的需求很多。防止有人交一份钱,把所有的课件就拷给了别人。这样的事情培训机构肯定是不愿意的。现在我项目里面也出了这么个需求。下面介绍一下我的实现
2022-06-06

c语言中的文件加密与解密

这篇文章主要介绍了c语言中的文件加密与解密方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-05-18

Linux命令行进行文件内容加密与解密处理

在Linux中,可以使用命令行工具对文件内容进行加密和解密处理安装GnuPG(GNU Privacy Guard,GPG):在Debian/Ubuntu系统上,使用以下命令安装GnuPG:sudo apt-get install gnup
Linux命令行进行文件内容加密与解密处理
2024-09-25

Windows批处理压缩包内加密pdf文件解密的操作步骤

批处理就是可以对文件进行批量处理,而不需要一个一个的去对文件执行相同的操作,这篇文章主要介绍了Windows批处理压缩包内加密pdf文件解密,需要的朋友可以参考下
2022-11-13

C#中常见的文件加密和解密算法问题

C#中常见的文件加密和解密算法问题,需要具体代码示例在现代计算机应用中,数据的保护和安全显得尤为重要。文件加密和解密算法是一种常用的数据安全保护措施,可以确保文件在传输和存储过程中不被未授权的人员访问和修改。本文将探讨C#中常见的文件加密和
2023-10-22

Springboot实现对配置文件中的明文密码加密详解

我们在SpringBoot项目当中,会把数据库的用户名密码等配置直接放在yaml或者properties文件中,这样维护数据库的密码等敏感信息显然是有一定风险的。所以本文为大家整理了对配置文件中的明文密码加密的方法,希望对大家有所帮助
2023-03-10

麒麟操作系统中的文件加密和解密如何保护你的隐私

麒麟操作系统中的文件加密和解密功能可以帮助保护用户的隐私。以下是它是如何工作的:1. 文件加密:麒麟操作系统提供了文件加密功能,用户可以选择对特定文件或文件夹进行加密。加密后的文件将被转换成不可读的密文,只有拥有正确解密密钥的人才能解密并访
2023-10-12

Go语言中如何处理并发文件的文件系统文件缓存和热加载问题?

Go语言中如何处理并发文件的文件系统文件缓存和热加载问题?引言:在Go语言中,处理文件系统文件的并发访问和缓存是一个常见而重要的问题。当系统中有多个Goroutine同时对同一个文件进行操作时,容易出现数据不一致或者竞争条件。另外,为了提高
2023-10-22

Go语言中如何处理并发文件的文件系统文件锁和进程间文件共享问题?

Go语言中处理并发文件的文件系统文件锁和进程间文件共享问题引言:在Go语言中,我们常常需要处理并发访问文件的情况,包括文件系统文件锁和进程间文件共享。本文将介绍如何使用Go语言处理这些问题,并提供具体的代码示例。一、文件系统文件锁在多个并发
2023-10-22

Go语言中如何处理并发文件的文件系统空间管理和磁盘容量限制问题?

Go语言是一种支持并发编程的高级编程语言,它在处理文件系统空间管理和磁盘容量限制问题上具有很大的优势。本文将介绍如何使用Go语言来处理并发文件的文件系统空间管理和磁盘容量限制问题,并提供相应的代码示例。在Go语言中,使用os包和io包可以方
2023-10-22

如何处理Go语言中的并发文件压缩解压缩问题?

如何处理Go语言中的并发文件压缩解压缩问题?文件压缩和解压缩是日常开发中经常遇到的任务之一。随着文件大小的增加,压缩和解压缩操作可能会变得非常耗时,因此并发处理成为提高效率的一个重要手段。在Go语言中,可以利用goroutine和chann
2023-10-22

如何处理Go语言中的并发文件压缩解压缩问题

在Go语言中处理并发文件压缩解压缩问题,可以使用goroutine和channel来实现。首先,你可以使用`io`包来读取文件,并将读取到的数据发送到一个channel中。同时,可以使用`sync.WaitGroup`来等待所有的文件读取操
2023-10-09

SQLServer 错误 33027 由于 Authenticode 签名或文件路径无效,未能加载加密提供程序“%.*ls”。 请检查以前的消息,了解其他失败信息。 故障 处理 修复 支持远程

详细信息 Attribute 值 产品名称 SQL Server 事件 ID 33027 事件源 MSSQLSERVER 组件 SQLEngine 符号名称 SEC_CRYPTOPROV_CANTLOADDLL ...
SQLServer 错误 33027 由于 Authenticode 签名或文件路径无效,未能加载加密提供程序“%.*ls”。 请检查以前的消息,了解其他失败信息。 故障 处理 修复 支持远程
2023-11-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录