🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。
  
📌 特别说明:
文中问题案例来源于真实生产环境与公开技术社区,并结合多位一线资深工程师与架构师的长期实践经验,经过人工筛选与AI系统化智能整理后输出。文中的解决方案并非唯一“标准答案”,而是兼顾可行性、可复现性与思路启发性的实践参考,供你在实际项目中灵活运用与演进。
  
欢迎你 关注、收藏并订阅本专栏,与持续更新的技术干货同行,一起让问题变资产,让经验可复制,技术跃迁,稳步向上。

📢 问题描述

详细问题描述如下:通过wx.createUserInfoButton,然后点击屏幕弹出了自定义弹窗,然后我点击同意,发送agree请求过去,报错:getUserInfo:fail click action before resolve is needed,这个需要怎么把agree发送过去?

📣 请知悉:如下方案不保证一定适配你的问题!

  如下是针对上述问题进行专业角度剖析答疑,不喜勿喷,仅供参考:

✅ 问题理解

🎯 核心问题分析

你遇到的错误:getUserInfo:fail click action before resolve is needed

这个错误的含义是:

  • 错误本质:微信要求用户点击授权按钮后,必须等待微信SDK内部的Promise resolve完成后,才能调用getUserInfo
  • 你的操作流程:点击按钮 → 弹出自定义弹窗 → 点击同意 → 发送请求 ❌
  • 正确流程:点击按钮 → 等待微信处理完点击事件 → 再获取用户信息 ✅

🔬 问题根源深度剖析

微信授权按钮的工作机制

为什么会有这个限制?

微信为了防止恶意获取用户信息,设计了这样的机制:

  1. 必须是真实的用户点击(不能模拟)
  2. 点击事件必须完整处理(不能被打用getUserInfo必须在点击事件的回调链中**

✅ 问题解决方案

🟢 方案 A:直接在tap回调中处理(推荐⭐⭐⭐⭐⭐)

这是最符合微信规范的做法,不需要自定义弹窗。

using UnityEngine;
using WeChatWASM;
using System;

public class WeChatAuthManager : MonoBehaviour
{
    private WXUserInfoButton userInfoButton;
    
    void Start()
    {
        CreateAuthButton();
    }
    
    /// <summary>
    /// 创建微信授权按钮
    /// </summary>
    void CreateAuthButton()
    {
        // 按钮样式配置
        var style = new WXUserInfoButtonStyle()
        {
            left = 10,
            top = 10,
            width = 200,
            height = 60,
            backgroundColor = "#FF0000",
            textAlign = "center",
            fontSize = 16,
            lineHeight = 40,
            borderRadius = 8
        };
        
        // 创建授权按钮
        userInfoButton = WX.CreateUserInfoButton(
            x: 10,
            y: 10,
            width: 200,
            height: 60,
            lang: "zh_CN",
            withCredentials: true
        );
        
        // ✅ 关键:在tap回调中直接处理授权
        userInfoButton.OnTap((result) =>
        {
            Debug.Log("🎉 用户点击了授权按钮");
            
            // 检查是否授权成功
            if (result.errMsg == "getUserInfo:ok")
            {
                Debug.Log("✅ 授权成功!");
                Debug.Log($"昵称: {result.userInfo.nickName}");
                Debug.Log($"头像: {result.userInfo.avatarUrl}");
                Debug.Log($"性别: {result.userInfo.gender}");
                Debug.Log($"国家: {result.userInfo.country}");
                Debug.Log($"省份: {result.userInfo.province}");
                Debug.Log($"城市: {result.userInfo.city}");
                
                // 🎯 在这里发送数据到服务器
                SendUserInfoToServer(result.userInfo, result.rawData, result.signature);
                
                // 隐藏授权按钮
                userInfoButton.Hide();
                
                // 显示游戏主界面
                ShowMainGameUI();
            }
            else
            {
                Debug.LogError($"❌ 授权失败: {result.errMsg}");
                ShowErrorMessage("授权失败,请重试");
            }
        });
        
        // 显示按钮
        userInfoButton.Show();
    }
    
    /// <summary>
    /// 发送用户信息到服务器
    /// </summary>
    void SendUserInfoToServer(WXUserInfo userInfo, string rawData, string signature)
    {
        // 构建请求数据
        var requestData = new
        {
            nickName = userInfo.nickName,
            avatarUrl = userInfo.avatarUrl,
            gender = userInfo.gender,
            country = userInfo.country,
            province = userInfo.province,
            city = userInfo.city,
            rawData = rawData,
            signature = signature,
            timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
        };
        
        string jsonData = JsonUtility.ToJson(requestData);
        
        Debug.Log($"📤 发送数据: {jsonData}");
        
        // 使用UnityWebRequest发送
        StartCoroutine(SendRequest(jsonData));
    }
    
    System.Collections.IEnumerator SendRequest(string jsonData)
    {
        using (UnityEngine.Networking.UnityWebRequest request = new UnityEngine.Networking.UnityWebRequest("https://your-server.com/api/userinfo", "POST"))
        {
            byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonData);
            request.uploadHandler = new UnityEngine.Networking.UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new UnityEngine.Networking.DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            
            yield return request.SendWebRequest();
            
            if (request.result == UnityEngine.Networking.UnityWebRequest.Result.Success)
            {
                Debug.Log($"✅ 服务器响应: {request.downloadHandler.text}");
            }
            else
            {
                Debug.LogError($"❌ 请求失败: {request.error}");
            }
        }
    }
    
    void ShowMainGameUI()
    {
        Debug.Log("🎮 显示游戏主界面");
        // 你的UI显示逻辑
    }
    
    void ShowErrorMessage(string message)
    {
        Debug.LogError($"⚠️ {message}");
        // 显示错误提示UI
    }
    
    void OnDestroy()
    {
        // 销毁按钮
        if (userInfoButton != null)
        {
            userInfoButton.Destroy();
        }
    }
}
🎯 方案A的优势:
  • 完全符合微信规范,不会报错
  • 代码简洁,逻辑清晰
  • 无需自定义弹窗,减少复杂度
  • 用户体验好,点击后立即处理

🟡 方案 B:使用微信官方弹窗 + 授权引导

如果你必须要有确认弹窗,可以使用微信的模态框:

using UnityEngine;
using WeChatWASM;

public class WeChatAuthWithModal : MonoBehaviour
{
    private WXUserInfoButton userInfoButton;
    private bool isAuthorizing = false;
    
    void Start()
    {
        // 先检查是否已授权
        CheckAuthStatus();
    }
    
    /// <summary>
    /// 检查授权状态
    /// </summary>
    void CheckAuthStatus()
    {
        WX.GetSetting(new GetSettingOption()
        {
            success = (result) =>
            {
                if (result.authSetting.ContainsKey("scope.userInfo") && 
                    result.authSetting["scope.userInfo"])
                {
                    Debug.Log("✅ 用户已授权,直接获取信息");
                    GetUserInfoDirectly();
                }
                else
                {
                    Debug.Log("⚠️ 用户未授权,显示授权引导");
                    ShowAuthGuide();
                }
            },
            fail = (error) =>
            {
                Debug.LogError($"❌ 获取设置失败: {error.errMsg}");
                ShowAuthGuide();
            }
        });
    }
    
    /// <summary>
    /// 显示授权引导
    /// </summary>
    void ShowAuthGuide()
    {
        // 使用微信模态框
        WX.ShowModal(new ShowModalOption()
        {
            title = "需要您的授权",
            content = "为了给您提供更好的游戏体验,我们需要获取您的昵称和头像",
            showCancel = true,
            cancelText = "暂不授权",
            confirmText = "立即授权",
            success = (result) =>
            {
                if (result.confirm)
                {
                    Debug.Log("✅ 用户点击了确认,创建授权按钮");
                    CreateAuthButton();
                }
                else if (result.cancel)
                {
                    Debug.Log("⚠️ 用户取消授权");
                    ShowGuestModeOption();
                }
            },
            fail = (error) =>
            {
                Debug.LogError($"❌ 显示模态框失败: {error.errMsg}");
            }
        });
    }
    
    /// <summary>
    /// 创建授权按钮(全屏透明按钮)
    /// </summary>
    void CreateAuthButton()
    {
        if (userInfoButton != null)
        {
            userInfoButton.Destroy();
        }
        
        // 创建全屏透明按钮,引导用户点击
        userInfoButton = WX.CreateUserInfoButton(
            x: 0,
            y: 0,
            width: Screen.width,
            height: Screen.height,
            lang: "zh_CN",
            withCredentials: true
        );
        
        // 设置样式为透明
        userInfoButton.style = new WXUserInfoButtonStyle()
        {
            left = 0,
            top = 0,
            width = Screen.width,
            height = Screen.height,
            backgroundColor = "rgba(0,0,0,0)", // 完全透明
            color = "rgba(0,0,0,0)",
            textAlign = "center",
            fontSize = 1,
            borderRadius = 0
        };
        
        // 在Canvas上显示一个提示UI
        ShowClickGuideUI();
        
        // ✅ 点击后立即处理
        userInfoButton.OnTap((result) =>
        {
            Debug.Log("🎯 用户点击了透明授权按钮");
            
            // 隐藏引导UI
            HideClickGuideUI();
            
            if (result.errMsg == "getUserInfo:ok")
            {
                Debug.Log("✅ 授权成功!");
                HandleAuthSuccess(result);
            }
            else
            {
                Debug.LogError($"❌ 授权失败: {result.errMsg}");
                HandleAuthFail(result.errMsg);
            }
            
            // 销毁按钮
            userInfoButton.Destroy();
            userInfoButton = null;
        });
        
        userInfoButton.Show();
    }
    
    /// <summary>
    /// 用户已授权,直接获取信息
    /// </summary>
    void GetUserInfoDirectly()
    {
        WX.GetUserInfo(new GetUserInfoOption()
        {
            withCredentials = true,
            lang = "zh_CN",
            success = (result) =>
            {
                Debug.Log("✅ 直接获取用户信息成功");
                HandleAuthSuccess(result);
            },
            fail = (error) =>
            {
                Debug.LogError($"❌ 获取用户信息失败: {error.errMsg}");
                // 可能授权已过期,重新引导
                ShowAuthGuide();
            }
        });
    }
    
    /// <summary>
    /// 处理授权成功
    /// </summary>
    void HandleAuthSuccess(WXUserInfoResponse result)
    {
        Debug.Log($"👤 用户信息:");
        Debug.Log($"   昵称: {result.userInfo.nickName}");
        Debug.Log($"   头像: {result.userInfo.avatarUrl}");
        
        // 发送到服务器
        SendUserInfoToServer(result);
        
        // 进入游戏
        EnterGame();
    }
    
    /// <summary>
    /// 处理授权失败
    /// </summary>
    void HandleAuthFail(string errMsg)
    {
        WX.ShowToast(new ShowToastOption()
        {
            title = "授权失败",
            icon = "none",
            duration = 2000
        });
        
        // 显示游客模式选项
        ShowGuestModeOption();
    }
    
    void SendUserInfoToServer(WXUserInfoResponse result)
    {
        // 发送逻辑(同方案A)
        Debug.Log("📤 发送用户信息到服务器...");
    }
    
    void ShowClickGuideUI()
    {
        Debug.Log("💡 显示点击引导UI");
        // 在Unity Canvas上显示一个遮罩和提示文字
        // 例如:"请点击屏幕完成授权"
    }
    
    void HideClickGuideUI()
    {
        Debug.Log("🚫 隐藏点击引导UI");
    }
    
    void ShowGuestModeOption()
    {
        Debug.Log("👻 显示游客模式选项");
    }
    
    void EnterGame()
    {
        Debug.Log("🎮 进入游戏");
    }
    
    void OnDestroy()
    {
        if (userInfoButton != null)
        {
            userInfoButton.Destroy();
        }
    }
}

🔴 方案 C:修复你当前的错误做法

如果你坚持使用自定义弹窗,需要彻底重构流程

using UnityEngine;
using WeChatWASM;

public class WeChatAuthFixed : MonoBehaviour
{
    private WXUserInfoButton userInfoButton;
    private WXUserInfoResponse cachedUserInfo; // 缓存授权结果
    
    void Start()
    {
        CreateInvisibleAuthButton();
    }
    
    /// <summary>
    /// 创建不可见的授权按钮
    /// </summary>
    void CreateInvisibleAuthButton()
    {
        // 创建一个小的、隐藏的按钮
        userInfoButton = WX.CreateUserInfoButton(
            x: -1000, // 移出屏幕
            y: -1000,
            width: 10,
            height: 10,
            lang: "zh_CN",
            withCredentials: true
        );
        
        userInfoButton.OnTap((result) =>
        {
            Debug.Log("🎯 授权按钮被点击");
            
            if (result.errMsg == "getUserInfo:ok")
            {
                // ✅ 缓存授权结果
                cachedUserInfo = result;
                Debug.Log("✅ 授权成功,缓存结果");
                
                // 显示自定义弹窗
                ShowCustomConfirmDialog();
            }
            else
            {
                Debug.LogError($"❌ 授权失败: {result.errMsg}");
            }
        });
        
        userInfoButton.Hide();
    }
    
    /// <summary>
    /// 用户点击你的自定义"开始游戏"按钮时调用
    /// </summary>
    public void OnCustomStartButtonClick()
    {
        Debug.Log("🖱️ 用户点击了自定义开始按钮");
        
        // 将真正的授权按钮移动到点击位置
        MoveAuthButtonToClickPosition();
        userInfoButton.Show();
        
        // 提示用户再次点击
        WX.ShowToast(new ShowToastOption()
        {
            title = "请点击屏幕授权",
            icon = "none"
        });
    }
    
    void MoveAuthButtonToClickPosition()
    {
        // 将授权按钮移动到屏幕中央
        userInfoButton.style = new WXUserInfoButtonStyle()
        {
            left = Screen.width / 2 - 100,
            top = Screen.height / 2 - 30,
            width = 200,
            height = 60,
            backgroundColor = "#07C160",
            color = "#FFFFFF",
            textAlign = "center",
            fontSize = 16,
            lineHeight = 40,
            borderRadius = 8
        };
    }
    
    /// <summary>
    /// 显示自定义确认弹窗
    /// </summary>
    void ShowCustomConfirmDialog()
    {
        Debug.Log("💬 显示自定义确认弹窗");
        
        // 这里可以显示你的Unity UI弹窗
        // 包含用户信息预览和"同意"按钮
        
        // 假设弹窗有一个Agree按钮
    }
    
    /// <summary>
    /// 用户点击"同意"按钮时调用
    /// </summary>
    public void OnAgreeButtonClick()
    {
        Debug.Log("✅ 用户点击了同意按钮");
        
        if (cachedUserInfo != null)
        {
            // ✅ 使用缓存的授权结果
            Debug.Log("📤 发送缓存的用户信息");
            SendUserInfoToServer(cachedUserInfo);
            
            // 隐藏弹窗
            HideCustomDialog();
            
            // 进入游戏
            EnterGame();
        }
        else
        {
            Debug.LogError("❌ 没有缓存的用户信息!");
        }
    }
    
    void SendUserInfoToServer(WXUserInfoResponse userInfo)
    {
        Debug.Log($"📤 发送用户信息: {userInfo.userInfo.nickName}");
        // 发送逻辑...
    }
    
    void HideCustomDialog()
    {
        Debug.Log("🚫 隐藏自定义弹窗");
    }
    
    void EnterGame()
    {
        Debug.Log("🎮 进入游戏");
        
        // 销毁授权按钮
        if (userInfoButton != null)
        {
            userInfoButton.Destroy();
        }
    }
}

⚠️ 方案C的缺点

  • 用户需要点击两次(体验不好)
  • 逻辑复杂,容易出错
  • 不推荐使用

✅ 问题延伸

🧩 微信小游戏授权机制深度解析

1️⃣ 授权方式对比
授权方式 适用场景 优点 缺点
wx.getUserInfo (已废弃) 简单 ❌ 已不可用
wx.getUserProfile 需要主动触发 每次都弹窗 体验差
wx.createUserInfoButton 推荐 符合规范 需要真实点击
开放数据域 排行榜等 无需授权 功能受限
2️⃣ 微信授权的安全机制
// 微信为什么要这样设计?

// ❌ 错误理解:点击按钮 → 立即获取信息
// 这样会导致:恶意开发者可以用透明按钮覆盖整个屏幕,
// 用户误触就泄露信息

// ✅ 正确理解:点击按钮 → 微信验证 → Promise resolve → 获取信息
// 确保:
// 1. 用户真实点击(不是代码模拟)
// 2. 点击事件完整(没有被中断或篡改)
// 3. 调用时机正确(在回调链中)
3️⃣ Unity与微信SDK交互的最佳实践
// 推荐的代码组织结构

public class WeChatSDKManager : MonoBehaviour
{
    // 单例模式
    public static WeChatSDKManager Instance { get; private set; }
    
    // 用户信息
    public WXUserInfo CurrentUser { get; private set; }
    public bool IsAuthorized { get; private set; }
    
    // 事件
    public event System.Action<WXUserInfo> OnAuthSuccess;
    public event System.Action<string> OnAuthFail;
    
    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
    public void StartAuth()
    {
        // 授权流程...
    }
    
    // 其他游戏逻辑通过事件监听授权结果
}
4️⃣ 常见的授权流程设计模式

模式A:启动时授权

应用启动 → 加载界面 → 检查授权状态 → 
→ 已授权:直接进入游戏
→ 未授权:显示授权引导 → 授权成功 → 进入游戏

模式B:延迟授权

应用启动 → 游客模式 → 用户游玩 → 
→ 需要社交功能时(如排行榜)→ 引导授权

✅ 问题预测

🔮 可能遇到的后续问题

⚠️ 问题1:iOS真机测试时授权按钮不显示

原因:iOS对WebView有限制

解决方案

// 检测平台
#if UNITY_IOS
    // iOS需要额外配置
    userInfoButton.style.zIndex = 9999;
#endif
⚠️ 问题2:用户取消授权后无法再次触发

解决方案

// 监听授权设置变化
WX.OnAuthSettingChange((result) =>
{
    Debug.Log("📢 授权设置发生变化");
    
    if (result.authSetting.ContainsKey("scope.userInfo"))
    {
        bool isAuthorized = result.authSetting["scope.userInfo"];
        Debug.Log($"用户信息授权状态: {isAuthorized}");
        
        if (!isAuthorized)
        {
            // 用户取消了授权,重新引导
            ShowAuthGuideAgain();
        }
    }
});
⚠️ 问题3:头像获取失败或模糊

原因:微信头像有多个尺寸

解决方案

string avatarUrl = userInfo.avatarUrl;

// 替换为高清头像
if (avatarUrl.Contains("/132"))
{
    avatarUrl = avatarUrl.Replace("/132", "/0"); // 0表示原图
}

Debug.Log($"🖼️ 高清头像URL: {avatarUrl}");
⚠️ 问题4:signature验证失败

后端验证代码示例(Node.js)

const crypto = require('crypto');

function verifySignature(rawData, sessionKey, signature) {
    const hash = crypto
        .createHmac('sha1', sessionKey)
        .update(rawData)
        .digest('hex');
    
    return hash === signature;
}

// Express路由
app.post('/api/userinfo', (req, res) => {
    const { rawData, signature } = req.body;
    const sessionKey = req.session.wechat_session_key; // 从登录时保存的
    
    if (verifySignature(rawData, sessionKey, signature)) {
        // 签名验证通过
        res.json({ success: true });
    } else {
        // 签名验证失败
        res.status(400).json({ error: 'Invalid signature' });
    }
});
⚠️ 问题5:多次点击导致重复请求

解决方案

private bool isProcessing = false;

userInfoButton.OnTap((result) =>
{
    if (isProcessing)
    {
        Debug.LogWarning("⚠️ 正在处理中,请勿重复点击");
        return;
    }
    
    isProcessing = true;
    
    try
    {
        // 处理授权逻辑...
    }
    finally
    {
        isProcessing = false;
    }
});

✅ 小结

📋 核心要点回顾

🎯 问题的本质

你的错误 getUserInfo:fail click action before resolve is needed 的根本原因是:

  1. 时序错误:在微信SDK的Promise resolve之前就调用了getUserInfo
  2. 流程错误:点击按钮 → 弹窗 → 发请求(中断了微信的事件链)
  3. 理解偏差:没有理解微信的安全机制
🔧 正确的解决方案
方案 推荐度 说明
🟢 方案A ⭐⭐⭐⭐⭐ 直接在tap回调中处理,最简单最稳定
🟡 方案B ⭐⭐⭐⭐ 使用微信官方弹窗,体验好
🔴 方案C ⭐⭐ 修复现有流程,不推荐
💡 最佳实践
// ✅ 推荐的授权流程
1. 创建WXUserInfoButton
2. 在OnTap回调中直接处理授权结果
3. 授权成功后发送数据到服务器
4. 进入游戏主逻辑

// ❌ 不推荐的流程
1. 创建WXUserInfoButton  
2. 点击后弹出自定义确认框
3. 用户确认后再发送请求 ← 这里会报错!
🚀 立即行动

步骤1:删除你当前的自定义弹窗逻辑

步骤2:使用方案A的代码替换

步骤3:测试流程:

点击授权按钮 → 检查控制台日志 → 
→ 看到"授权成功" → 数据发送成功 → 完成!

步骤4:如果必须要确认弹窗,使用方案B的WX.ShowModal

🎁 额外提示

// 调试技巧:打印详细日志
userInfoButton.OnTap((result) =>
{
    Debug.Log("=== 授权回调开始 ===");
    Debug.Log($"errMsg: {result.errMsg}");
    Debug.Log($"rawData: {result.rawData}");
    Debug.Log($"signature: {result.signature}");
    Debug.Log($"userInfo: {JsonUtility.ToJson(result.userInfo)}");
    Debug.Log("=== 授权回调结束 ===");
    
    // 你的处理逻辑...
});

🎉 最后

你遇到的问题核心就是:不能打断微信SDK的授权事件链

解决方法就是:OnTap回调中直接完成所有逻辑,不要弹出自定义确认框再处理。

如果你实在需要确认弹窗,就用微信官方的WX.ShowModal在授权按钮之前显示,用户确认后再创建授权按钮。

现在就试试方案A吧! 保证一次成功!

有任何问题随时问我!

🌹 结语 & 互动说明

希望以上分析与解决思路,能为你当前的问题提供一些有效线索或直接可用的操作路径

若你按文中步骤执行后仍未解决:

  • 不必焦虑或抱怨,这很常见——复杂问题往往由多重因素叠加引起;
  • 欢迎你将最新报错信息、关键代码片段、环境说明等补充到评论区;
  • 我会在力所能及的范围内,结合大家的反馈一起帮你继续定位 👀

💡 如果你有更优或更通用的解法:

  • 非常欢迎在评论区分享你的实践经验或改进方案;
  • 你的这份补充,可能正好帮到更多正在被类似问题困扰的同学;
  • 正所谓「赠人玫瑰,手有余香」,也算是为技术社区持续注入正向循环

🧧 文末福利:技术成长加速包 🧧

  文中部分问题来自本人项目实践,部分来自读者反馈与公开社区案例,也有少量经由全网社区与智能问答平台整理而来。

  若你尝试后仍没完全解决问题,还请多一点理解、少一点苛责——技术问题本就复杂多变,没有任何人能给出对所有场景都 100% 套用的方案。

  如果你已经找到更适合自己项目现场的做法,非常建议你沉淀成文档或教程,这不仅是对他人的帮助,更是对自己认知的再升级。

  如果你还在持续查 Bug、找方案,可以顺便逛逛我专门整理的 Bug 专栏:《全栈 Bug 调优(实战版)》
这里收录的都是在真实场景中踩过的坑,希望能帮你少走弯路,节省更多宝贵时间。

✍️ 如果这篇文章对你有一点点帮助:

  • 欢迎给 bug菌 来个一键三连:关注 + 点赞 + 收藏
  • 你的支持,是我持续输出高质量实战内容的最大动力。

同时也欢迎关注我的硬核公众号 「猿圈奇妙屋」

获取第一时间更新的技术干货、BAT 等互联网公司最新面试真题、4000G+ 技术 PDF 电子书、简历 / PPT 模板、技术文章 Markdown 模板等资料,统统免费领取
你能想到的绝大部分学习资料,我都尽量帮你准备齐全,剩下的只需要你愿意迈出那一步来拿。

🫵 Who am I?

我是 bug菌:

  • 热活跃于 CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等技术社区;
  • CSDN 博客之星 Top30、华为云多年度十佳博主/卓越贡献者、掘金多年度人气作者 Top40;
  • 掘金、InfoQ、51CTO 等平台签约及优质作者;
  • 全网粉丝累计 30w+

更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看 👈️
硬核技术公众号 「猿圈奇妙屋」 期待你的加入,一起进阶、一起打怪升级。

- End -

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐