跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
TypeScriptNode.js大前端

UniApp 集成鸿蒙华为一键登录 Account Kit 实战

在 UniApp 项目中集成鸿蒙华为一键登录(Account Kit)的完整流程。文章涵盖了从华为开发者平台配置、插件结构设计、UTS 插件层核心实现(JS API 与原生按钮组件)、客户端 Vue 页面编写到后端 Express 验证示例的全链路开发指南。重点讲解了 authorizationCode 的安全流转机制、state 防 CSRF 措施、条件编译处理以及 OpenID 与 UnionID 的区别。通过封装通用插件,实现了用户无需手动输入即可快速获取手机号并完成登录,显著提升了鸿蒙生态下的用户体验与转化率。

DevOpsTeam发布于 2026/3/22更新于 2026/9/985 浏览
UniApp 集成鸿蒙华为一键登录 Account Kit 实战

什么是华为一键登录

华为 Account Kit 提供的一键登录能力,本质上是这样一个流程:用户点击登录按钮 → 华为系统弹出授权面板,展示当前华为账号绑定的手机号(脱敏显示)→ 用户确认授权 → 客户端拿到一个 authorizationCode → 把这个 code 发给你的后端 → 后端拿 code 去华为服务器换取真实手机号 → 完成登录。

整个过程用户不需要手动输入任何信息,体验非常丝滑。

Account Kit 提供两种主要能力:

能力说明获取内容
华为账号授权登录获取用户基本资料昵称、头像、OpenID、UnionID
一键登录(quickLoginAnonymousPhone)获取手机号匿名手机号 + authorizationCode(后端换真实号码)

整体架构

先看整体的技术架构,理解各层之间的关系:

  • 服务端:Express 后端,处理 JWT Token 签发与手机号验证。
  • 鸿蒙原生层:jack-hwilogin 插件,包含 index.uts (JS API) 和 login.ets (原生按钮组件)。
  • 客户端:Vue 页面,通过 embed 标签或 JS API 调用。
  • 华为授权服务:提供 AccountKit - AuthenticationController 与 LoginWithHuaweiIDButton。

关键点在于:客户端永远拿不到真实手机号,只能拿到匿名手机号和授权码。真实手机号的获取必须走服务端,这是华为出于安全考虑的设计。

前置准备

在写代码之前,需要先在华为开发者平台完成一些配置工作:

  1. 登录 AppGallery Connect 创建你的应用。
  2. 在「API 管理」中开通 Account Kit(帐号服务)。
  3. 记录下你的 Client ID 和 Client Secret,后端验证要用。
  4. 配置应用的签名证书指纹(SHA-256),这个很重要,指纹不匹配的话授权页面拉不起来。

重点说一下容易忽略的:签名证书指纹一定要和你实际打包用的证书一致,开发阶段用的调试证书和发布证书的指纹是不同的,别搞混了。

插件结构

插件目录结构很简洁:

uni_modules/jack-hwilogin/ └── utssdk/ └── app-harmony/ ├── index.uts # JS API(huaweiLogin / getPhoneNumber) └── login.ets # 原生登录按钮组件(embed 方式) 

两个文件各司其职:index.uts 提供函数式调用,适合你想自定义按钮样式的场景;login.ets 封装了华为官方的登录按钮组件,通过 embed 标签嵌入 Vue 页面,样式合规且用户体验更好。

核心实现:UTS 插件层

JS API 方式 (index.uts)

这个文件导出两个核心函数:huaweiLogin(获取用户资料)和 getPhoneNumber(获取手机号,一键登录场景)。

import './login.ets'
import { authentication } from '@kit.AccountKit'
import { hilog }  
 { util }  
 {  }  
 { common }  

  = 


  {
  : 
  : 
  : 
  : 
  : 
}

  {
  :  
  :  
}

  {
  : 
  : 
  : 
  ?: 
  ?: 
}

  {
  :  
  :  
}


  ():  {
   {
     loginRequest =  authentication.().()
    loginRequest. = 
    loginRequest. = []
    loginRequest. = []
    loginRequest. = util.()
    loginRequest. = util.()
    loginRequest. = authentication..

     context = ()  common.
     controller =  authentication.(context)

    controller.(loginRequest,  {
       (error) {
        hilog.(, , )
        options. && options.()
        
      }
       response = data  authentication.
      
       (response. && loginRequest. !== response.) {
        hilog.(, , )
        options. && options.()
        
      }
       credential = response?.
       :  = {
        : credential?. ?? ,
        : credential?. ?? ,
        : credential?. ?? ,
        : credential?. ?? ,
        : credential?. ?? 
      }
      options. && options.(userInfo)
    })
  }  (error) {
    hilog.(, , )
    options. && options.()
  }
}


  ():  {
   {
     loginRequest =  authentication.().()
    loginRequest. = 
    loginRequest. = []
    loginRequest. = []
    loginRequest. = util.()

     context = ()  common.
     controller =  authentication.(context)

    controller.(loginRequest,  {
       (error) {
        hilog.(, , )
        options. && options.()
        
      }
       response = data  authentication.
       (response. && loginRequest. !== response.) {
        options. && options.()
        
      }
       credential = response?.
       :  = {
        : credential?. ?? ,
        : credential?. ?? ,
        : credential?. ?? ,
        : credential?.?.   | ,
        : credential?.?.   | 
      }
      options. && options.(phoneInfo)
    })
  }  (error) {
    hilog.(, , )
    options. && options.()
  }
}
from
'@kit.PerformanceAnalysisKit'
import
from
'@kit.ArkTS'
import
BusinessError
from
'@kit.BasicServicesKit'
import
from
'@kit.AbilityKit'
const
TAG
'JackHWILogin'
// ========== 类型定义 ==========
interface
HuaweiUserInfo
authorizationCode
string
openID
string
unionID
string
nickName
string
avatarUri
string
interface
HuaweiLoginOptions
success
(data: HuaweiUserInfo) =>
void
fail
(err: string) =>
void
interface
PhoneInfo
authorizationCode
string
openID
string
unionID
string
anonymousPhone
string
isLocalPhone
boolean
interface
GetPhoneOptions
success
(data: PhoneInfo) =>
void
fail
(err: string) =>
void
/** * 华为账号登录 —— 获取用户基本信息 */
export
function
huaweiLogin
options: HuaweiLoginOptions
void
try
const
new
HuaweiIDProvider
createAuthorizationWithHuaweiIDRequest
forceAuthorization
true
scopes
'profile'
permissions
'serviceauthcode'
state
generateRandomUUID
nonce
generateRandomUUID
idTokenSignAlgorithm
IdTokenSignAlgorithm
PS256
const
getContext
as
UIAbilityContext
const
new
AuthenticationController
executeRequest
(error: BusinessError<Object>, data) =>
if
error
0x0000
TAG
`Login failed: ${JSON.stringify(error)}`
fail
fail
`登录失败:${error.message || '未知错误'}`
return
const
as
AuthorizationWithHuaweiIDResponse
// 验证 state,防止 CSRF 攻击
if
state
state
state
error
0x0000
TAG
`State mismatch`
fail
fail
'状态验证失败'
return
const
data
const
userInfo
HuaweiUserInfo
authorizationCode
authorizationCode
''
openID
openID
''
unionID
unionID
''
nickName
nickName
''
avatarUri
avatarUri
''
success
success
catch
error
0x0000
TAG
`Exception: ${error}`
fail
fail
`登录异常:${error}`
/** * 获取手机号 —— 一键登录场景 */
export
function
getPhoneNumber
options: GetPhoneOptions
void
try
const
new
HuaweiIDProvider
createAuthorizationWithHuaweiIDRequest
forceAuthorization
true
scopes
'quickLoginAnonymousPhone'
permissions
'serviceauthcode'
state
generateRandomUUID
const
getContext
as
UIAbilityContext
const
new
AuthenticationController
executeRequest
(error: BusinessError<Object>, data) =>
if
error
0x0000
TAG
`Get phone failed: ${JSON.stringify(error)}`
fail
fail
`获取手机号失败:${error.message}`
return
const
as
AuthorizationWithHuaweiIDResponse
if
state
state
state
fail
fail
'状态验证失败'
return
const
data
const
phoneInfo
PhoneInfo
authorizationCode
authorizationCode
''
openID
openID
''
unionID
unionID
''
anonymousPhone
extraInfo
quickLoginAnonymousPhone
as
string
undefined
isLocalPhone
extraInfo
localNumberConsistency
as
boolean
undefined
success
success
catch
error
0x0000
TAG
`Exception: ${error}`
fail
fail
`获取手机号异常:${error}`

说几个关键设计点:

  1. scopes 的区别是两个函数最核心的差异。huaweiLogin 用的是 ['profile'],请求用户的昵称头像等基本资料;getPhoneNumber 用的是 ['quickLoginAnonymousPhone'],请求手机号授权。两者返回的数据结构不同,所以我分成了两个独立函数,调用方按需选择。
  2. state 防 CSRF 是个容易被忽略但很重要的安全措施。每次请求我都用 util.generateRandomUUID() 生成一个随机 state,回调时校验 response 里的 state 是否一致。如果不一致,说明响应可能被篡改,直接拒绝。
  3. forceAuthorization = true 表示每次都强制拉起授权页面,即使用户之前已经授权过。这样做的好处是每次都能拿到新的 authorizationCode,避免 code 过期的问题。
原生按钮组件 (login.ets)

除了 JS API,我还封装了华为官方的 LoginWithHuaweiIDButton 组件。这个组件的好处是样式由华为官方提供,符合品牌规范,而且用户看到熟悉的华为登录按钮会更有信任感。

import { defineNativeEmbed, NativeEmbedBuilderOptions } from '@dcloudio/uni-app-runtime'
import { loginComponentManager, LoginWithHuaweiIDButton } from '@kit.AccountKit'
import { hilog } from '@kit.PerformanceAnalysisKit'
import { BusinessError } from '@kit.BasicServicesKit'

const TAG = 'HuaweiLoginButton'

interface LoginButtonOptions extends NativeEmbedBuilderOptions {}

interface LoginSuccessData {
  authorizationCode?: string
  unionID?: string
  openID?: string
  success: boolean
  err: string
}

interface LoginEvent {
  type: string
  detail: LoginSuccessData
}

@Component
struct HuaweiLoginButtonComponent {
  onSuccess?: Function
  onFail?: Function

  private controller: loginComponentManager.LoginWithHuaweiIDButtonController = new loginComponentManager.LoginWithHuaweiIDButtonController()
    .setAgreementStatus(loginComponentManager.AgreementStatus.ACCEPTED)
    .onClickLoginWithHuaweiIDButton((error: BusinessError, response: loginComponentManager.HuaweiIDCredential) => {
      if (error) {
        hilog.error(0x0000, TAG, `Login failed: ${error.code}${error.message}`)
        this.handleFail(`登录失败:${error.code}${error.message}`)
      } else {
        hilog.info(0x0000, TAG, `Login success`)
        this.handleSuccess(response)
      }
    })
    .onClickEvent((error: BusinessError, clickEvent: loginComponentManager.ClickEvent) => {
      hilog.info(0x0000, TAG, `Button clicked: ${clickEvent}`)
    })

  private handleSuccess(response: loginComponentManager.HuaweiIDCredential): void {
    if (this.onSuccess) {
      const event: LoginEvent = {
        type: 'success',
        detail: {
          authorizationCode: response.authorizationCode,
          unionID: response.unionID,
          openID: response.openID,
          success: true,
          err: 'ok'
        }
      }
      this.onSuccess(event)
    }
  }

  private handleFail(errorMsg: string): void {
    if (this.onFail) {
      const event: LoginEvent = {
        type: 'fail',
        detail: { success: false, err: errorMsg }
      }
      this.onFail(event)
    }
  }

  build() {
    LoginWithHuaweiIDButton({
      params: {
        style: loginComponentManager.Style.BUTTON_CUSTOM,
        loginType: loginComponentManager.LoginType.QUICK_LOGIN,
        supportDarkMode: true
      },
      controller: this.controller
    }).width('100%').height('100%')
  }
}

// 组件构建器
@Builder
function HuaweiLoginButtonBuilder(opts: LoginButtonOptions) {
  HuaweiLoginButtonComponent({
    onSuccess: opts?.on?.get('success'),
    onFail: opts?.on?.get('fail')
  }).width(opts.width).height(opts.height)
}

// 注册为原生嵌入组件,Vue 页面通过 <embed tag="hwilogin" /> 使用
defineNativeEmbed('hwilogin', { builder: HuaweiLoginButtonBuilder })

这里有个 uni-app 鸿蒙开发的知识点:defineNativeEmbed 是 uni-app 运行时提供的 API,用于将鸿蒙原生组件注册为可在 Vue 页面中通过 <embed> 标签使用的组件。tag 参数就是你在 Vue 模板里写的标签名,事件通过 opts.on.get('eventName') 获取。

loginType: LoginType.QUICK_LOGIN 表示使用快速登录模式,系统会自动展示当前华为账号的手机号。setAgreementStatus(ACCEPTED) 表示用户已同意隐私协议——这个状态需要你在业务层自己判断,我在 Vue 页面里做了隐私政策勾选的校验。

客户端完整页面

下面是我实际项目中的注册/登录页面完整代码,直接可用:

<template>
  <view>
    <!-- Logo 区域 -->
    <view class="logo-section">
      <image src="/static/logo.png" mode="aspectFit"></image>
      <text class="app-name">示例 APP</text>
      <text class="slogan">成长好帮手</text>
    </view>

    <!-- 登录表单卡片 -->
    <view class="form-card">
      <view class="form-title">用户注册</view>

      <!-- 华为账号登录按钮(原生组件) -->
      <!-- #ifdef APP-HARMONY -->
      <view class="huawei-login-section">
        <embed tag="hwilogin" :options="huaweiOptions" @success="handleHuaweiLoginSuccess" @fail="handleHuaweiLoginFail"></embed>
        <text>请使用华为账号登录</text>
      </view>
      <!-- #endif -->

      <!-- 登录链接 -->
      <view class="login-link">
        <text>已有账号?</text>
        <text class="link-btn" @click="goToLogin">立即登录</text>
      </view>

      <!-- 隐私政策勾选 -->
      <view class="privacy-check">
        <view class="checkbox-wrapper" @click="agreePrivacy = !agreePrivacy">
          <view class="checkbox" :class="{ checked: agreePrivacy }">
            <text v-if="agreePrivacy">✓</text>
          </view>
        </view>
        <text class="privacy-text">我已阅读并同意</text>
        <text class="privacy-link" @click.stop="goToPrivacy">《隐私政策》</text>
      </view>
    </view>
  </view>
</template>

<script>
import { huaweiLogin } from '@/utils/api.js'
import { setToken, setUserInfo } from '@/utils/auth.js'

// #ifdef APP-HARMONY
import '@/uni_modules/jack-hwilogin'
// #endif

export default {
  name: 'Register',
  data() {
    return {
      agreePrivacy: false,
      huaweiOptions: {}
    }
  },
  methods: {
    // 华为登录成功回调
    async handleHuaweiLoginSuccess({ detail }) {
      console.log('华为登录成功:', detail)
      // 必须先同意隐私政策
      if (!this.agreePrivacy) {
        uni.showToast({ title: '请先同意隐私政策', icon: 'none', duration: 2000 })
        return
      }
      try {
        uni.showLoading({ title: '登录中...' })
        // 将 authorizationCode 发送到后端验证
        const res = await huaweiLogin({
          authorizationCode: detail.authorizationCode,
          unionId: detail.unionID,
          openId: detail.openID
        })
        if (res.success) {
          setToken(res.token)
          setUserInfo(res.user)
          uni.hideLoading()
          if (res.isNewUser) {
            uni.showToast({ title: '注册成功', icon: 'success' })
          } else {
            uni.showToast({ title: '登录成功', icon: 'success' })
          }
          setTimeout(() => {
            uni.switchTab({ url: '/pages/index/index' })
          }, 1500)
        }
      } catch (err) {
        uni.hideLoading()
        console.error('华为登录失败:', err)
      }
    },
    // 华为登录失败回调
    handleHuaweiLoginFail(err) {
      console.error('华为登录失败:', err)
      uni.showToast({ title: '华为登录失败,请重试', icon: 'none' })
    },
    goToLogin() {
      uni.navigateBack()
    },
    goToPrivacy() {
      uni.navigateTo({ url: '/pages/privacy/index' })
    }
  }
}
</script>

<style scoped>
.register-page {
  min-height: 100vh;
  background: #f5f5f5;
  position: relative;
  padding-bottom: 120rpx;
}
.header-bg {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 500rpx;
  background: linear-gradient(135deg, #FF9A9E, #FECFEF);
  border-radius: 0 0 60rpx 60rpx;
}
.logo-section {
  position: relative;
  padding-top: 80rpx;
  text-align: center;
}
.logo {
  width: 140rpx;
  height: 140rpx;
  border-radius: 30rpx;
  box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
}
.app-name {
  display: block;
  margin-top: 20rpx;
  font-size: 36rpx;
  font-weight: bold;
  color: #fff;
}
.slogan {
  display: block;
  margin-top: 8rpx;
  font-size: 24rpx;
  color: rgba(255, 255, 255, 0.8);
}
.form-card {
  position: relative;
  margin: 40rpx 40rpx 0;
  padding: 40rpx;
  background: #fff;
  border-radius: 30rpx;
  box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.1);
}
.form-title {
  text-align: center;
  font-size: 36rpx;
  font-weight: bold;
  color: #333;
  margin-bottom: 40rpx;
}
.huawei-login-section {
  margin-bottom: 30rpx;
}
.huawei-login-btn {
  display: block;
  width: 100%;
  height: 96rpx;
  margin-bottom: 20rpx;
}
.login-link {
  margin-top: 30rpx;
  text-align: center;
}
.link-text {
  font-size: 28rpx;
  color: #999;
}
.link-btn {
  font-size: 28rpx;
  color: #FF9A9E;
  font-weight: bold;
}
.privacy-check {
  display: flex;
  align-items: center;
  margin-top: 30rpx;
}
.checkbox-wrapper {
  padding: 10rpx;
}
.checkbox {
  width: 40rpx;
  height: 40rpx;
  border: 2rpx solid #ddd;
  border-radius: 8rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24rpx;
  color: #fff;
}
.checkbox.checked {
  background: linear-gradient(135deg, #FF9A9E, #FECFEF);
  border-color: #FF9A9E;
}
.privacy-text {
  font-size: 26rpx;
  color: #666;
  margin-left: 10rpx;
}
.privacy-link {
  font-size: 26rpx;
  color: #FF9A9E;
}
</style>

注意 import '@/uni_modules/jack-hwilogin' 这行,它的作用是触发 login.ets 中的 defineNativeEmbed 注册。如果不 import,<embed tag="hwilogin"> 就找不到对应的原生组件。另外整个 import 和 embed 标签都包在 #ifdef APP-HARMONY 条件编译里,这样在其他平台编译时不会报错。

登录时序

整个一键登录的完整时序如下:

  1. 用户勾选隐私政策。
  2. 点击华为登录按钮,embed 组件触发登录。
  3. 执行 executeRequest(quickLoginAnonymousPhone),弹出授权面板(显示脱敏手机号)。
  4. 用户确认授权,返回 authorizationCode + anonymousPhone + OpenID + UnionID。
  5. @success 回调,前端将 authorizationCode 发送给后端 /api/auth/huawei-login。
  6. 后端调用华为 oauth2/v6/quickLogin/getPhoneNumber 接口换取真实手机号。
  7. 后端创建/更新用户记录,签发 JWT Token。
  8. 前端保存 Token,跳转首页。

后端验证示例

客户端拿到 authorizationCode 后,需要发给后端去华为服务器换取真实手机号。下面是一个简化的 Express 后端示例:

const express = require('express')
const axios = require('axios')
const jwt = require('jsonwebtoken')

const app = express()
app.use(express.json())

// 华为账号服务配置(从 AGC 后台获取)
const HUAWEI_CONFIG = {
  clientId: 'your_client_id',
  clientSecret: 'your_client_secret',
  apiUrl: 'https://account-api.cloud.huawei.com/oauth2/v6/quickLogin/getPhoneNumber'
}

const JWT_SECRET = 'your_jwt_secret'

/**
 * 华为一键登录接口
 * 接收客户端传来的 authorizationCode,向华为服务器换取真实手机号
 */
app.post('/api/auth/huawei-login', async (req, res) => {
  try {
    const { authorizationCode, unionId, openId } = req.body
    if (!authorizationCode || !unionId || !openId) {
      return res.status(400).json({ success: false, message: '缺少必需参数' })
    }

    // 第一步:用 authorizationCode 向华为服务器换取真实手机号
    let phoneNumber = null
    try {
      const response = await axios.post(HUAWEI_CONFIG.apiUrl, {
        code: authorizationCode,
        clientId: HUAWEI_CONFIG.clientId,
        clientSecret: HUAWEI_CONFIG.clientSecret
      }, {
        headers: { 'Content-Type': 'application/json;charset=UTF-8' }
      })
      if (response.data && response.data.phoneNumber) {
        phoneNumber = response.data.phoneNumber
      } else {
        return res.status(400).json({ success: false, message: '获取手机号失败' })
      }
    } catch (apiError) {
      console.error('华为 API 调用失败:', apiError.message)
      return res.status(500).json({ success: false, message: '华为账号服务异常' })
    }

    // 第二步:根据 unionId 查找或创建用户
    // 这里用伪代码表示数据库操作,实际项目中替换为你的 ORM
    let user = await db.findUserByUnionId(unionId)
    let isNewUser = false
    if (!user) {
      // 新用户,创建记录
      user = await db.createUser({
        huaweiUnionId: unionId,
        huaweiOpenId: openId,
        phone: phoneNumber,
        loginType: 'huawei'
      })
      isNewUser = true
    } else {
      // 老用户,更新手机号等信息
      await db.updateUser(user.id, { huaweiOpenId: openId, phone: phoneNumber })
    }

    // 第三步:签发 JWT Token
    const token = jwt.sign({ userId: user.id }, JWT_SECRET, { expiresIn: '7d' })

    res.json({
      success: true,
      token,
      isNewUser,
      user: {
        id: user.id,
        phone: phoneNumber,
        nickname: user.nickname
      }
    })
  } catch (error) {
    console.error('登录失败:', error)
    res.status(500).json({ success: false, message: '服务器错误' })
  }
})

app.listen(3000, () => console.log('Server running on port 3000'))

后端的核心逻辑就三步:拿 code 换手机号 → 查找/创建用户 → 签发 Token。华为的 getPhoneNumber 接口需要传 code(就是客户端给你的 authorizationCode)、clientId 和 clientSecret,返回的 phoneNumber 就是用户的真实手机号。

这里要注意 clientSecret 绝对不能暴露在客户端代码里,只能放在服务端。

踩坑与注意事项

授权页面拉不起来

大概率是签名证书指纹的问题。在 AGC 后台配置的 SHA-256 指纹必须和你打包用的证书完全一致。开发阶段换了调试证书记得同步更新。另外确认 Account Kit 服务已经在 AGC 后台开通。

authorizationCode 只能用一次

华为返回的 authorizationCode 是一次性的,后端用它换完手机号之后就失效了。如果你的后端接口因为网络问题重试,第二次调用华为 API 会失败。建议在后端做好幂等处理。

条件编译不能少

所有涉及 @kit.AccountKit 的代码都只能在鸿蒙平台运行。Vue 页面里的 import 和模板都要用 #ifdef APP-HARMONY 包裹,否则在其他平台编译会报错。

OpenID vs UnionID

OpenID 是同一个应用下唯一的用户标识,不同应用拿到的 OpenID 不同。UnionID 是同一个开发者账号下唯一的,如果你有多个 App 需要打通用户体系,应该用 UnionID 作为用户关联的主键。

总结

华为一键登录的接入并不复杂,核心就是理解 authorizationCode 的流转:客户端获取 → 传给后端 → 后端去华为换手机号。该方案提供了 JS API 和原生按钮两种方式,基本覆盖了常见的登录场景。

目录

  1. 什么是华为一键登录
  2. 整体架构
  3. 前置准备
  4. 插件结构
  5. 核心实现:UTS 插件层
  6. JS API 方式 (index.uts)
  7. 原生按钮组件 (login.ets)
  8. 客户端完整页面
  9. 登录时序
  10. 后端验证示例
  11. 踩坑与注意事项
  12. 总结

更多推荐文章

查看全部
  • Python 属性描述符:原理剖析与 ORM 实战
  • 小厂架构师实战:AI Agent 辅助 Bug 定位与修复
  • 《Agent Runtime 工程化》第五章 上下文工程:5.1 token budget 是产品预算
  • 医疗连续体机器人模块化控制界面设计与 Python 库应用研究
  • 2026 年 3 月 23 日 AI 产业要闻:脑机接口落地与算力竞赛
  • 鸿蒙金融理财全栈项目:上线运维、用户反馈与持续迭代
  • Linux 库的制作与原理
  • OpenClaw Web Search 工具配置与渠道选择指南
  • AI Agent 设计模式实战:ReAct 架构详解
  • Python 七大学习路线详解
  • Ubuntu 20.04 安装 Ollama 与 Open WebUI 部署大模型指南
  • 单核 CPU 可抢占优先级任务调度算法解析
  • 百川 2-13B-Chat-4bits WebUI 部署:Supervisor 配置文件 baichuan-webui.conf 详解
  • 大模型时代:个人与企业的 AI Ready 对齐
  • ERNIE-4.5 系列模型单卡部署与心理健康机器人应用
  • 高并发内存池大页内存申请释放及定长内存池优化
  • Node.js 在线 Markdown 编辑器:支持表格、公式与代码高亮
  • Whisper-large-v3 持续集成:GitHub Actions 自动测试与模型版本灰度发布
  • LLM 学习路径:从入门到精通技术指南
  • 前端状态管理:Recoil 的原子化方案

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online