liziyu 发布的文章

本人 MacOS系统如下所示:
QQ20230822-093612@2x.png

按照Wails安装步骤时,出现“zsh: command not found: wails”的问题,于是Goolge搜索并找到如下的解决方案:

https://github.com/wailsapp/wails/issues/2046

解决办法在https://github.com/wailsapp/wails/issues/2046#issuecomment-1376535844

On my MacOs Ventura:
Installed go => it is installed to "/usr/local/go"
Installed wails => it is installed in "~go/bin/wails"
Result: "zsh: command not found: wails"
QuickFix for me: sudo cp ~/go/bin/wails /usr/local/go/bin/

其实就这一句话:sudo cp ~/go/bin/wails /usr/local/go/bin/

Fyne一款golang的桌面,对中文支持不够友好,解决办法:
1、环境变量FYNE_FONT=ttf文件路径。
2、代码设置环境变量,如下:

func init(){
    os.Setenv("FYNE_FONT","./yahei.ttf")
}

注意,上面两种办法任一种都可以。

const (
    MININT64 = -922337203685477580
    MAXINT64 = 9223372036854775807
)
 
 
func Max(nums... int64) int64 {
    var maxNum int64 = MININT64
    for _, num := range nums {
        if num > maxNum {
            maxNum = num
        }
    }
    return maxNum
}
 
 
 
 
func Min(nums... int64) int64 {
    var minNum int64 = MAXINT64
    for _, num := range nums {
        if num < minNum {
            minNum = num
        }
    }
    return minNum 
}
 
 
 
func Sum(nums... int64) int64 {
    var sumNum int64 = 0
    for _, num := range nums {
            sumNum += num
    }
    return sumNum 
}

以上是对整形的实现,浮点型需要使用math.Max包下的函数更为科学严谨。

package main

import (
    "context"
    "github.com/wechatpay-apiv3/wechatpay-go/core"
    "github.com/wechatpay-apiv3/wechatpay-go/core/option"
    "github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
    "github.com/wechatpay-apiv3/wechatpay-go/utils"
    "log"
    "time"
)

func main() {

    var (
        mchID                      string = "xxxx"                               // 商户号
        mchCertificateSerialNumber string = "xxxxx" // 商户证书序列号
        mchAPIv3Key                string = "xxxxxx"         // 商户APIv3密钥
    )

    // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
    mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./apiclient_key.pem")
    if err != nil {
        log.Fatal("load merchant private key error")
    }

    ctx := context.Background()
    // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力
    opts := []core.ClientOption{
        option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
    }
    client, err := core.NewClient(ctx, opts...)
    if err != nil {
        log.Printf("new wechat pay client err:%s", err)
    }

    svc := native.NativeApiService{Client: client}
    resp, result, err := svc.Prepay(ctx,
        native.PrepayRequest{
            Appid:       core.String("xxxxxxx"),
            Mchid:       core.String("1650242918"),
            Description: core.String("Image形象店-深圳腾大-QQ公仔"),
            OutTradeNo:  core.String("1217752501201407033233368018"),
            TimeExpire:  core.Time(time.Now()),
            Attach:      core.String("自定义数据说明"),
            NotifyUrl:   core.String("https://www.weixin.qq.com/wxpay/pay.php"),
            GoodsTag:    core.String("WXG"),
            //LimitPay:      []string{"LimitPay_example"},
            SupportFapiao: core.Bool(false),
            Amount: &native.Amount{
                Currency: core.String("CNY"),
                Total:    core.Int64(1),
            },
            Detail: &native.Detail{
                CostPrice: core.Int64(608800),
                GoodsDetail: []native.GoodsDetail{native.GoodsDetail{
                    GoodsName:        core.String("iPhoneX 256G"),
                    MerchantGoodsId:  core.String("ABC"),
                    Quantity:         core.Int64(1),
                    UnitPrice:        core.Int64(828800),
                    WechatpayGoodsId: core.String("1001"),
                }},
                InvoiceId: core.String("wx123"),
            },
            SettleInfo: &native.SettleInfo{
                ProfitSharing: core.Bool(false),
            },
            SceneInfo: &native.SceneInfo{
                DeviceId:      core.String("013467007045764"),
                PayerClientIp: core.String("14.23.150.211"),
                StoreInfo: &native.StoreInfo{
                    Address:  core.String("广东省深圳市南山区科技中一道10000号"),
                    AreaCode: core.String("440305"),
                    Id:       core.String("0001"),
                    Name:     core.String("腾讯大厦分店"),
                },
            },
        },
    )

    if err != nil {
        log.Println("\n用我了")
        // 处理错误
        log.Printf("call Prepay err:%s", err)
    } else {
        log.Println("\n正确的结果为:")
        // 处理返回结果
        log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
    }
}

注意修改商户相关参数。

func BytesToString(b []byte) (s string) {
    _bptr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
    _sptr := (*reflect.StringHeader)(unsafe.Pointer(&s))
    _sptr.Data = _bptr.Data
    _sptr.Len = _bptr.Len
    return s
}

// 随机生成字符串
func RandomString(l int) string {
    str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"
    bytes := []byte(str)
    var result []byte = make([]byte, 0, l)
    r := rand.New(rand.NewSource(time.Now().UnixNano()))
    for i := 0; i < l; i++ {
        result = append(result, bytes[r.Intn(len(bytes))])
    }
    return BytesToString(result)
}

func main() {
    fmt.Println(RandomString(64))
}

1.Nginx 实现一个 IP 访问总流量限制

http {
    limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
    limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
    # 其他配置
}
server {
    listen 80;
    server_name example.com;

    # 限制单个客户端 IP 最大连接数为 2
    limit_conn conn_zone 2;
    # 限制单个客户端 IP 1s 内最多发起 1 个请求
    limit_req zone=req_zone burst=5;
    # 计算客户端 IP 累计请求流量,限制累计请求流量为 1GB
    set $limit_rate 128k;
    limit_rate_after 500M;
    limit_rate 1m;
    # 其他处理逻辑
}

2. 统计服务器所有 url 被请求的数量

#统计其他端口时:netstat -pnt | grep :xx | wc -l
netstat -pnt | grep :443 | wc -l

3. 查找请求数前 20 个 IP

#服务器被恶意高频访问时可以用到
netstat -ant |awk '/:443/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}' |sort -rn|head -n20

4. 统计文件中某个字符转出现的次数

#如统计文件api_error.log中error关键词出现的次数
grep -o 'error' /www/payment/runtime/logs/api_error.log | wc -l

5. 监听文件

#可以监听整个文件,也可根据关键词监听
cd /www/payment/runtime/logs/

tail -f xxx.log #监听整个文件
tail -f xxx.log | grep 'xxx' #根据关键词监听

6. 查看文件大小

#以下是本人开发中常用到的
一、du命令
du命令是查看使用空间的,但是与df命令不同的是Linux du命令是对文件和目录磁盘使用的空间的查看,还是和df命令有一些区别的。

du -h filepath 直接得出人好识别的文件大小

du -h ljl.txt

或者
du -ah 当前目录下所有文件的大小

二、ls命令
ls命令用来显示目标列表,在Linux中是使用率较高的命令。ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件。

ls -l filepath 第五列为文件字节数

ls -l ljl.txt

ls -h filepath h表示human, 加-h参数得到人好读的文件大小

ls -lh ljl.txt

7. 查看 ip 来源地

#使用这个是为了查看异常登录地址
yum -y install whois
whois 119.53.224.203

8. 查看磁盘使用情况

df -h

9. 创建软链接

ln -s [源文件或目录] [目标文件或目录]

例如:创建软链时,先进入根目录的bin目录下

cd /bin

从/bin这个路径创建软链nginx 引入/usr/local/nginx/sbin/nginx

ln -s /usr/local/nginx/sbin/nginx nginx

创建软链之后 重载nginx 
就可以从 /usr/local/nginx/sbin/nginx -s reload 简化为 nginx -s reload

10. 查看是否监听 9000 端口(其他端口雷同)

netstat -ant | grep 9000

11.Nginx 解决跨域问题

#server模块中添加以下内容,修改完后,记得重启nginx
add_header  Access-Control-Allow-Headers '*';
add_header  Access-Control-Allow-Origin '*';
add_header  Access-Control-Allow-Credentials 'true';
add_header  Access-Control-Allow-Methods 'GET,POST,OPTIONS';

#跨域参数解释
#Access-Control-Allow-Origin:服务器默认是不被允许跨域的。给Nginx服务器配置Access-Control-Allow-Origin *后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。
#Access-Control-Allow-Methods:允许通过的方法,可以防止Content-Type is not allowed by Access-Control-Allow-Headers in preflight response的错误信息
#Access-Control-Allow-Credentials true 表示允许跨域请求携带 cookie
#Access-Control-Allow-Headers:为了防止出现Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response的错误信息。这个错误表示当前请求Content-Type的值不被支持。其实是我们发起了”application/json”的类型请求导致的

12.Nginx 配置 ssl (小白看过来)

server {
    listen 443 ssl;#监听443端口
    #server_name 购买域名后解析到该服务器上,如果没有域名,也可以给此项目单独开端口
    server_name  api.applet.xxx.com;
    root        /xxx/xxxx/xxxx;#root 项目地址
    index       index.php index.html index.htm;#项目入口文件

    #存放证书的地址.pem和.key文件
    ssl_certificate /usr/local/nginx/conf/vhost/cert/xxx.pem;
    ssl_certificate_key /usr/local/nginx/conf/vhost/cert/xxx.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    if (!-e $request_filename){
        rewrite ^/(.*) /index.php last;
    }

    location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
    }
    error_log  /var/log/nginx/api_applet.log error;
}

13.Nginx 开放防火墙端口

#这里讲到的是CentOS7,CentOS7的防火墙和CentOS6不一样了, CentOS 6 系列中的 iptables 相关命令不能用了,Centos7中使用firewalld代替了原来的iptables。

#停止firewall
systemctl stop firewalld.service

#禁止firewall开机启动
systemctl disable firewalld.service

#添加8022端口
firewall-cmd --zone=public --add-port=8022/tcp --permanent

#多个端口:
firewall-cmd --zone=public --add-port=80-90/tcp --permanent

#命令含义:
--zone #作用域
--add-port=8022/tcp #添加端口,格式为:端口/通讯协议
--permanent #永久生效,没有此参数重启后失效

#centos7查看防火墙所有信息
firewall-cmd --list-all

#centos7查看防火墙开放的端口信息
firewall-cmd --list-ports

#删除8022端口
firewall-cmd --zone=public --remove-port=8022/tcp --permanent

#重启防火墙
firewall-cmd --reload

常用命令介绍:
firewall-cmd --state                ##查看防火墙状态,是否是running
firewall-cmd --reload               ##重新载入配置,比如添加规则之后,需要执行此命令
firewall-cmd --get-zones            ##列出支持的zone
firewall-cmd --get-services         ##列出支持的服务,在列表中的服务是放行的
firewall-cmd --query-service ftp    ##查看ftp服务是否支持,返回yes或者no
firewall-cmd --add-service=ftp      ##临时开放ftp服务
firewall-cmd --add-service=ftp --permanent     ##永久开放ftp服务
firewall-cmd --remove-service=ftp --permanent  ##永久移除ftp服务
firewall-cmd --add-port=80/tcp --permanent     ##永久添加80端口

转自:https://learnku.com/articles/78462

package main

import (
    "log"
)

type Notifier interface {
    Notify() error
}

type User struct {
    Name  string
    Email string
}

func (u *User) Notify() error {
    log.Printf("User: Sending user Email To %s<%s>", u.Name, u.Email)
    return nil
}

func SendNotification(notify Notifier) error {
    return notify.Notify()
}

func main() {
    user := User{
        Name:  "liziyu",
        Email: "13073932@163.com",
    }
    //user.Notify()
    SendNotification(user)
    //cannot use user (variable of type User) as Notifier value in argument to SendNotification: User does not implement Notifier (method Notify has pointer receiver)
}

cannot use user (variable of type User) as Notifier value in argument
to SendNotification: User does not implement Notifier (method Notify
has pointer receiver)

原因:

上面的错误说明Notify方法的接受者是指针类型的,因此User类型的值并没有实现该方法,也就是没有实现Notifier接口,不能作为参数传入。

为什么编译器不认为值类型实现了接口呢?确定接口是否被实现的规则是基于这些方法的接收者以及如何进行接口调用。下面是关于编译器如何确定类型的值或指针是否实现接口的规则:

指针类型(T)的方法集包含接受者是值类型(T)和指针类型(T)的方法。

该规则表明,如果用于调用接口方法的变量是指针,那么不管方法的接受者是值类型还是指针类型都可以被调用。此规则不适用于我们的示例,因为我们向SendNotification函数传递一个值不是指针。

值类型(T)的方法集只包含所有接受者为值类型(T)的方法

该规则表明,如果我们用于调用接口的变量是值类型,那么只有接收者也是值类型的方法才能满足接口。此规则不适用于我们的示例,因为Notify方法的接收者是一个指针。

换句话说:

接收者为值类型(T)的方法集不包含接收者为指针类型(*T)的方法。

这就是我们的前面代码报错的情况。Notify方法的接收者是指针,我们使用值进行接口方法调用会报错。要解决这个问题,我们只需要将User值的地址传递给SendNotification函数即可:
func main() {
    user := &User{
        Name:  "liziyu",
        Email: "13073932@163.com",
    }

    SendNotification(user)
}

// Output:
User: Sending User Email To liziyu<13073932@163.com>



最后用两句不太严谨的话总结一下:

1、当类型(结构体或标准类型)对象为“值类型”时,该对象只能调用它的接受者为“值类型”的接口方法。
2、当类型(结构体或标准类型)对象为“指针类型”时,该对象不但能调用它的接受者为“值类型”的接口方法,还能调用接受者为“指针类型”的接口方法。

->>>>>>>>>>>>>>>>>>>>>>以下代码有同工异曲之妙<<<<<<<<<<<<<<<<<<-

type F interface {
  f()
}

type S1 struct{}

func (s S1) f() {}

type S2 struct{}

func (s *S2) f() {}

s1Val := S1{}
s1Ptr := &S1{}
s2Val := S2{}
s2Ptr := &S2{}

var i F
i = s1Val
i = s1Ptr
i = s2Ptr

//  下面代码无法通过编译。因为 s2Val 是一个值,而 S2 的 f 方法中没有使用值接收器
//   i = s2Val
//   i.f() 报错 :cannot use s2Val (variable of type S2) as F value in assignment: S2 does not implement F (method f has pointer receiver)

QQ20230625-113225@2x.png

链接:https://www.jianshu.com/p/59a73d426e59

1、new (T) 为每个新的类型 T 分配一片内存,初始化为零值,并且返回类型为 * T 的内存地址,这种方法返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。

2、make(T) 返回一个类型为 T 的初始值,它只适用于 3 种内建的引用类型:slice、map 和 channel类型。

new () 是一个函数,不要忘记它的括号

1、使用微信提供的证书工具生成微信支付商户证书

apiclient_cert.pem, apiclient_key.pem

2、使用 cmd 生成微信支付商户证书序列号

openssl x509 -in apiclient_key.pem -noout -serial

3、使用 cmd 生成微信支付平台证书 (需要 composer 安装 wechatpay/wechatpay)

# -k: 微信支付商户 APIv3 密钥, -m: 商户号, -f: 商户的私钥文件路径, -s: 商户证书序列号, -o: 平台证书保存路径
php vendor\bin\CertificateDownloader.php -k 03ea86*** -m 16442*** -f ***\storage\cert\apiclient_key.pem -s 1208B*** -o ***\Desktop\WXCertUtil\cert

4、完整配置信息

# 微信支付 APP
# APP ID
WECHAT_APP_ID=***
# 微信支付商户 ID
WECHAT_MCH_ID=***
# 微信支付商户 APIv2 密钥
WECHAT_MCH_SECRET=***
# 微信支付商户 APIv3 密钥
WECHAT_MCH_V3_SECRET=***
# 微信支付商户证书序列号
WECHAT_SERIAL=***
# 微信支付商户证书路径
WECHAT_CERT=***\storage\cert\apiclient_cert.pem
WECHAT_KEY=***\storage\cert\apiclient_key.pem
# 微信支付平台证书序列号
WECHAT_PLATFORM_SERIAL=***
# 微信支付平台证书路径
WECHAT_PLATFORM_PEM=***\storage\cert\wechatpay.pem

转自:https://learnku.com/articles/78016
感谢作者的辛苦付出。