Bbili-open-mcpMCP
★

接口签名和状态码

guide#2接口签名实现标准和状态码

签名#

  • 不是所有接口都需要实现该接口,本签名为特定接口的请求签名,如相关文档没注明需要公共签名或者文档有单独签名说明,请根据具体接口文档提示进行签名

请求规范#

接入前请确保已入驻开放平台,且创建开放平台应用以获取client_id和app_secret 需使用B站侧提供的签名算法及header头信息进行返回; 加密时client_id和app_secret以B站侧提供的信息为准;

签名算法#

公共参数#

下表描述的公共请求头(Request Header)适用于通过URL发送HTTP请求调用API。

名称类型是否必填描述
AcceptString是接受的返回结果的类型。目前只支持JSON类型。取值:application/json
Content-TypeString是当前请求体(Request Body)的数据类型。取值:application/json或multipart/form-data
x-bili-content-md5String是请求体的编码值,根据请求体计算所得(全小写字母)。

算法说明:将body的请求体内容(除文件外)当作字符串进行MD5编码。
如果为GET请求或者请求的body为空,x-bili-content-md5的值请直接使用空字符串(string.Empty)进行求md5。
x-bili-timestampString是unix时间戳,单位是秒。请求时间戳不能超过当前时间10分钟,否则请求会被丢弃。
x-bili-signature-methodString是签名方式。取值:HMAC-SHA256
x-bili-signature-nonceString是全网签名唯一随机数。用于防止网络重放攻击,建议您每一次请求都使用不同的随机数,例如GUID。
x-bili-accesskeyidString是B站侧给出的Access Key(申请应用时获得的client_id)
x-bili-signature-versionString是如无单独说明,请取值2.0
access-tokenString否x-bili-signature-version为2.0时必填,为通过OAuth2授权获取到的access_token
AuthorizationString是请求签名。关于请求签名的计算方法,请参见签名机制。

签名算法#

签名算法使用HMAC-SHA256

编码格式#

请求必须为UTF-8编码

签名机制#

1.构建完整的待签名字符串#

抽取带"x-bili-"前缀的自定义header,按字典排序拼接,构建完整的待签名字符串:

  • 请注意:
    • 待签名字符串包含换行符\n
    • 如果为GET请求或者请求的body为空,x-bili-content-md5的值请直接使用空字符串(string.Empty)进行求md5
Plain-text
"x-bili-accesskeyid:$accesskeyidValue"
"x-bili-content-md5:$contentMd5Value"
"x-bili-signature-method:HMAC-SHA256"
"x-bili-signature-nonce:$signatureNonceValue"
"x-bili-signature-version:2.0"
"x-bili-timestamp:$timestamp"

待签名字符串示例:

Plain-text
x-bili-accesskeyid:xxxx
x-bili-content-md5:fa6837e35b2f591865b288dfd859ce9d
x-bili-signature-method:HMAC-SHA256
x-bili-signature-nonce:ad184c09-095f-91c3-0849-230dd3744045
x-bili-signature-version:2.0
x-bili-timestamp:1624594467
2.生成签名#

对步骤1中得到的字符串,使用app_secret进行HMAC-SHA256算法进行签名。

go示例代码如下:

go
func HmacSHA256(key string, data string) string {
    mac := hmac.New(sha256.New, []byte(key))
    mac.Write([]byte(data))
    return hex.EncodeToString(mac.Sum(nil))
}

将最后签名得到的字符串添加到Header的Authorization字段中

签名验证工具#

工具运行环境需要为Windows 64位环境


如果是其他系统环境,或上面下载的工具不可用,请到 Releases 进行下载

签名机制参考Demo#

签名算法C#版本Demo

签名机制参考DEMO(Go)#
go
package main

import (
    "crypto/hmac"
    "crypto/md5"
    "crypto/sha256"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "github.com/monaco-io/request"
    "sort"
    "strconv"
    "strings"
    "time"
)

type BaseResp struct {
    Code      int64       `json:"code"`
    Message   string      `json:"message"`
    RequestId string      `json:"request_id"`
    Data      interface{} `json:"data"`
}

const (
    ClientIdProd    = "yourclientid"
    AppSecretProd   = "yoursecret"
    AccessTokenProd = "youraccesstoken"
)

const (
    AcceptHeader              = "Accept"
    ContentTypeHeader         = "Content-Type"
    AuthorizationHeader       = "Authorization"
    JsonType                  = "application/json"
    HmacSha256                = "HMAC-SHA256"
    BiliTimestampHeader       = "x-bili-timestamp"
    BiliSignatureMethodHeader = "x-bili-signature-method"
    BiliSignatureNonceHeader  = "x-bili-signature-nonce"
    BiliAccessKeyIdHeader     = "x-bili-accesskeyid"
    BiliSignVersionHeader     = "x-bili-signature-version"
    BiliContentMD5Header      = "x-bili-content-md5"
    AccessToken               = "access-token"
    BiliVersionV2             = "2.0"

    MainOpenPlatformHttpHost = "https://member.bilibili.com"

)

type CommonHeader struct {
    ContentType       string
    ContentAcceptType string
    Timestamp         string
    SignatureMethod   string
    SignatureVersion  string
    Authorization     string
    Nonce             string
    AccessKeyId       string
    ContentMD5        string
    X1BilispyColor    string
    AccessToken       string
}



// ApiRequestV2 http request demo方法
func ApiRequestV2(reqJson, requestUrl string) (resp BaseResp, err error) {
    resp = BaseResp{}
    header := &CommonHeader{
       AccessToken:       AccessTokenProd,
       ContentType:       JsonType,
       ContentAcceptType: JsonType,
       Timestamp:         strconv.FormatInt(time.Now().Unix(), 10),
       SignatureMethod:   HmacSha256,
       SignatureVersion:  BiliVersionV2,
       Authorization:     "",
       Nonce:             strconv.FormatInt(time.Now().UnixNano(), 10), //用于幂等,记得替换
       AccessKeyId:       ClientIdProd,
       ContentMD5:        Md5(reqJson),
       //X1BilispyColor:    model.Color,
    }
    header.Authorization = CreateSignature(header, AppSecretProd)
    cli := request.Client{
       Method: "POST",
       URL:    fmt.Sprintf("%s%s", MainOpenPlatformHttpHost, requestUrl),
       Header: ToMap(header),
       String: reqJson,
    }

    // 打印请求的cURL命令
    fmt.Println("cURL Command:")
    cli.PrintCURL()

    var respTest interface{}
    cliResp := cli.Send().Scan(&respTest)
    if !cliResp.OK() {
       err = fmt.Errorf("[error] req:%+v resp:%+v err:%+v", reqJson, resp, cliResp.Error())
    }
    // 使用json.MarshalIndent来格式化JSON数据
    jsonData, err := json.MarshalIndent(respTest, "", "    ")
    if err != nil {
       fmt.Println("Error marshaling JSON:", err)
       return
    }

    // 打印格式化后的JSON字符串
    fmt.Println(string(jsonData))
    return
}

// CreateSignature 生成Authorization加密串
func CreateSignature(header *CommonHeader, accessKeySecret string) string {
    sStr := ToSortedString(header)
    return HmacSHA256(accessKeySecret, sStr)
}

// Md5 md5加密
func Md5(str string) (md5str string) {
    data := []byte(str)
    has := md5.Sum(data)
    md5str = fmt.Sprintf("%x", has)
    return md5str
}

// HmacSHA256 HMAC-SHA256算法
func HmacSHA256(key string, data string) string {
    mac := hmac.New(sha256.New, []byte(key))
    mac.Write([]byte(data))
    return hex.EncodeToString(mac.Sum(nil))
}

// ToMap 所有字段转map<string, string>
func ToMap(h *CommonHeader) map[string]string {
    return map[string]string{
       BiliTimestampHeader:       h.Timestamp,
       BiliSignatureMethodHeader: h.SignatureMethod,
       BiliSignatureNonceHeader:  h.Nonce,
       BiliAccessKeyIdHeader:     h.AccessKeyId,
       BiliSignVersionHeader:     h.SignatureVersion,
       BiliContentMD5Header:      h.ContentMD5,
       AuthorizationHeader:       h.Authorization,
        ContentTypeHeader:         h.ContentType,
       AcceptHeader:              h.ContentAcceptType,
       AccessToken: h.AccessToken,
    }
}

// ToSortMap 参与加密的字段转map<string, string>
func ToSortMap(h *CommonHeader) map[string]string {
    return map[string]string{
       BiliTimestampHeader:       h.Timestamp,
       BiliSignatureMethodHeader: h.SignatureMethod,
       BiliSignatureNonceHeader:  h.Nonce,
       BiliAccessKeyIdHeader:     h.AccessKeyId,
       BiliSignVersionHeader:     h.SignatureVersion,
       BiliContentMD5Header:      h.ContentMD5,
    }
}

// ToSortedString 生成需要加密的文本
func ToSortedString(h *CommonHeader) (sign string) {
    hMap := ToSortMap(h)
    var hSil []string
    for k := range hMap {
       hSil = append(hSil, k)
    }
    sort.Strings(hSil)
    for _, v := range hSil {
       sign += v + ":" + hMap[v] + "\n"
    }
    sign = strings.TrimRight(sign, "\n")
    return
}

第三方平台约定返回结构体#

名称类型是否必填例子描述
codeint是0返回码,业务错误码参考下方。
messagestring是success返回信息,业务错误信息参考下方。
dataobject是业务信息。
request_idstring是abcd123456每次请求生成的唯一id,用于问题排查。

状态码#

<!--

状态码排查工具#

开放平台接口的状态码查询,可直接进入【状态码查询工具】 -->

状态码列表#

请求通用错误#

错误码含义
4000参数错误(一般是缺少参数)
4001配置无效
4002签名异常
4003请求过期
4004重复请求
4005签名method异常
4006签名版本异常
4007Content-Type不为application/json
4008MD5校验失败
4009Accept不为application/json
4010服务异常
4011内部错误
4012BizCode不支持该方法

OAuth2:#

错误码含义
122000client_id错误
122001client_secret 错误
122002code未找到
122007refreshToken不合法
122008app_id不匹配
122009系统繁忙,获取用户数据失败,请稍后再试
122010系统异常,相关用户操作失败

鉴权与限频限流:#

错误码含义
127000缺少鉴权参数
127001access_token验证错误
127002sign验证错误
127003缺少mid或mid不匹配
127004client_id验证错误
127005机构认证未通过
127006应用认证未通过
127007应用无该接口权限
127008mid验证失败
127009接口请求次数达到上限
127010sign白名单验证错误
127011该接口用户未授权
127022upload_token验证错误
127023client_token校验错误
错误码含义
127009接口繁忙,请稍后再试
127304接口访问受限,请确认应用已申请相关权限,且授权账号状态正常
127305白名单限制
127306接口请求频率过高,请确保请求量正常。如果使用量大请联系运营进行相关业务咨询

视频稿件:#

错误码含义
123001账号无权限操作
123002服务不可用
123003该类型不支持投稿
123004不存在该稿件
123005稿件已经被删除
123006异常视频提交
123007当前稿件已锁定
123008参数错误
123009该分区不存在
123010该稿件类型不合法
123011该活动不存在
123012Tag参数不合法
123013标题不合法
123014描述信息不合法
123015新增稿件同一个标题短时间内不能重复提交
123016稿件转载来源不能为空
123017稿件描述长度为零
123018稿件描述长度太长,已超过限制
123019稿件描述类型不存在或者不匹配
123020稿件描述类型和对应的分区类型不匹配
123021稿件描述类型和对应的创作类型不匹配
123022第(%d)个Tag已被封印
123023投稿暂不可用
123024当前输入有敏感信息,请修正
123026您投稿的频率过快,请稍等30秒
123027转载类型稿件不支持活动参加哦~
123028稿件后台处理中,请10秒后再尝试
123029当前总提交视频个数已经超过上限
123030稿件标题过长,已经超过80个字符
123033第(%d)个视频的标题过长,已经超过80个字符
123034开放联合投稿权限前的稿件,不可编辑为合作稿件
123035当前稿件已开放,不允许再次设置定时发布,请刷新列表查看
123036非正式会员单日只能投递五个稿件,赶紧去答题转正吧
123037您当前等级太低,无法投稿,请先答题到1级,谢谢
123038封面不允许使用gif
123039网络繁忙 请稍后再试
123040不存该视频
123041该视频已经被UP主删除
123042视频提交需要二次确认
123043稿件任务已被取消
123044新人单P 系统升级中,敬请谅解
123045定时发布设置错误
123046视频章节内容含有非法字符
123047当前话题和分区不匹配,请重新选择话题或者分区
123048活动话题不允许修改
123049当前话题无效
123050投稿需要图片验证
123051投稿图片验证失败
123052您投稿的内容不符合平台社区规范
123053稿件批量提交时mtime校验失败
123054稿件提交时mtime校验失败
123055稿件审核机器提交时mtime校验失败
123056稿件审核人工提交时mtime校验失败

专栏#

错误码含义
129000相同标题的专栏短时间内不能重复提交
129001专栏不存在
129002分类错误
129003标签错误
129004封面图地址错误
129005专栏标题含有特殊文字或者标题长度大于40
129006正文要超过200字以上或者超过三张图哦
129009创建失败,文集数量达到上限
129010文集标题不合法
129012添加失败,文章数量达到上限
129015文集状态不能修改
129018当日投稿数量已到达上限
129020系统繁忙,获取专栏信息失败,请稍后再试
129021系统异常,相关专栏操作失败
129022文件上传失败,请检查后重试

用户管理#

错误码含义
122009系统繁忙,获取用户数据失败,请稍后再试
122010系统异常,相关用户操作失败

直播长链#

错误码含义
141001没有订阅的CMD
141002心跳超时
141003心跳不存在
141004用户没有直播间
141005获取长连失败

服务市场#

错误码含义
130001未授权的店铺信息
130002店铺信息不存在
130003参数错误
130004订单服务异常
130005系统繁忙,获取服务市场数据失败,请稍后再试
130006系统异常,服务市场操作失败
130007文件上传失败,请检查后重试

创作中心#

错误码含义
131001系统繁忙,获取数据失败,请稍后再试

原始文档:002_接口签名和状态码.md(19791 字节)。用 bili_docs_get { "ref": "2" } 读全文,用 bili_docs_search { "query": "…" } 检索。