{"record":{"id":"17936ec3e8be09b9","repo":"lyswhut/lx-music-desktop","slug":"error-17936e","errorCode":null,"errorMessage":"获取评论失败","messagePattern":"获取评论失败","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/utils/musicSdk/wy/comment.js","lineNumber":146,"sourceCode":"      method: 'post',\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',\n        origin: 'https://music.163.com',\n        Refere: 'http://music.163.com/',\n      },\n      form: weapi({\n        cursor: cursorInfo.cursor,\n        offset: cursorInfo.offset,\n        orderType: cursorInfo.orderType,\n        pageNo: page,\n        pageSize: limit,\n        rid: id,\n        threadId: id,\n      }),\n    })\n    const { body, statusCode } = await _requestObj.promise\n    // console.log(body)\n    if (statusCode != 200 || body.code !== 200) throw new Error('获取评论失败')\n    cursorTools.setCursor(songmid, body.data.cursor, cursorInfo.orderType, cursorInfo.offset, page)\n    return { source: 'wy', comments: this.filterComment(body.data.comments), total: body.data.totalCount, page, limit, maxPage: Math.ceil(body.data.totalCount / limit) || 1 }\n  },\n  async getHotComment({ songmid }, page = 1, limit = 100) {\n    if (this._requestObj2) this._requestObj2.cancelHttp()\n\n    const id = 'R_SO_4_' + songmid\n    page = page - 1\n\n    const _requestObj2 = httpFetch(`https://music.163.com/weapi/v1/resource/hotcomments/${id}`, {\n      method: 'post',\n      headers: {\n        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36',\n        origin: 'https://music.163.com',\n        Refere: 'http://music.163.com/',\n      },\n      form: weapi({\n        rid: id,","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/lyswhut/lx-music-desktop/blob/9c364b482e5621a1d38b50e8610d2fb974457e6e/src/renderer/utils/musicSdk/wy/comment.js#L128-L164","documentation":"Thrown by Netease Cloud Music's getComment when the weapi-encrypted comment endpoint at https://music.163.com/weapi/comment/resource/comments/get returns non-200 or body.code !== 200 (numeric). Uses cursor-based pagination via cursorTools (a stateful cursor manager keyed by songmid). The weapi() function encrypts the request body with Netease's proprietary algorithm. Reads body.data.comments, body.data.totalCount, and body.data.cursor.","triggerScenarios":"The weapi encryption is broken (Netease updates their encryption keys or algorithm). cursorTools returns an invalid/stale cursor for the given page. Rate-limiting or IP-banning by Netease (common for non-CN IPs). The songmid is invalid or the song has no comment thread. Network interference with music.163.com.","commonSituations":"Netease rotates their weapi secret/key, breaking all encrypted requests. Running the app from outside China triggers Netease IP-level blocking (returns non-200 or error code). The cursor state becomes corrupted when the user switches songs rapidly (cursorTools has stale data for a different songmid).","solutions":["Log body.code and statusCode to distinguish encryption failure from rate-limiting.","Verify the weapi encryption keys are up to date by testing other Netease weapi endpoints.","Ensure cursorTools is keyed correctly by songmid and cleared when switching songs.","Use a CN-based proxy/VPN if running from outside China.","Retry with backoff for transient rate-limiting."],"exampleFix":"// before\nconst { body, statusCode } = await _requestObj.promise\nif (statusCode != 200 || body.code !== 200) throw new Error('获取评论失败')\n\n// after\nconst { body, statusCode } = await _requestObj.promise\nif (statusCode != 200 || !body || body.code !== 200) {\n  console.warn('wy getComment failed', { statusCode, code: body?.code, msg: body?.msg })\n  throw new Error('获取评论失败')\n}","handlingStrategy":"try-catch","validationCode":"function hasWySongmid({ songmid }) {\n  return typeof songmid === 'string' && songmid.length > 0\n}","typeGuard":"function isWyCommentResponse(body) {\n  return body != null && typeof body === 'object' && body.code === 200 && body.data != null && body.data.comments != null\n}","tryCatchPattern":"try {\n  const result = await wyComment.getComment({ songmid }, page, limit)\n} catch (err) {\n  if (err.message === '获取评论失败') {\n    console.warn('Netease comments unavailable for', songmid, '(check weapi keys / IP blocking)')\n    return { source: 'wy', comments: [], total: 0, page, limit, maxPage: 1 }\n  }\n  throw err\n}","preventionTips":["Keep weapi encryption keys updated — Netease rotates them periodically.","Ensure cursorTools is correctly keyed by songmid and cleared on song change.","Use a CN-based proxy if running from outside China to avoid IP blocking.","Log body.code and body.msg to diagnose encryption vs. rate-limiting.","Retry with backoff for transient rate-limiting."],"tags":["netease","comments","network","api-contract","weapi-encryption","cursor","https","rate-limiting"],"backgroundTag":null,"analyzedSha":"9c364b482e5621a1d38b50e8610d2fb974457e6e","analyzedAt":"2026-08-12T15:14:48.244Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}