线上环境中,用户通过微博注册后,直接使用微博授权接口返回的用户信息显示头像发现显示的是一个叉叉;而在新窗口中打开头像时,返回的是 403 Forbidden 错误。诡异的是,开发环境通过 localhost 域名访问却是一切正常。

很明显,初步判断是微博做了防盗链所致。

然而,图片不像 API 接口,可以通过添加 referrer 头解决跨域和防盗链的问题,因此,也很明显,解决办法只能在自己的服务器端缓存一份微博头像。

So,代码实现就很简单了:

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
async saveWeiboUserAvatar(user: WeiboUser, userId: string) { const avatarUrl = user.avatar_hd; const avatarFormat = avatarUrl.split('?')[0].split('.').pop() || 'jpg'; const pathPrefix = (await this.optionService.getOptionByKey('avatar_path')).optionValue; const pathAvatar = pathPrefix + '/' + userId + '.' + avatarFormat; try { mkdirp.sync(pathPrefix); await this.commonService.saveFileFromURL(avatarUrl, pathAvatar); } catch (e) { throw new CustomException({ ... }); } }
async saveWeiboUserAvatar(user: WeiboUser, userId: string) { const avatarUrl = user.avatar_hd; const avatarFormat = avatarUrl.split('?')[0].split('.').pop() || 'jpg'; const pathPrefix = (await this.optionService.getOptionByKey('avatar_path')).optionValue; const pathAvatar = pathPrefix + '/' + userId + '.' + avatarFormat; try { mkdirp.sync(pathPrefix); await this.commonService.saveFileFromURL(avatarUrl, pathAvatar); } catch (e) { throw new CustomException({ ... }); } }

其中,saveFileFromURL 方法如下(参见:《Nest.js 爬虫实现图片保存和下载》一文):

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
async saveFileFromURL(url: string, path: string) { const writer = createWriteStream(path); const response = await this.httpService.axiosRef({ url, method: 'GET', responseType: 'stream' }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); }
async saveFileFromURL(url: string, path: string) { const writer = createWriteStream(path); const response = await this.httpService.axiosRef({ url, method: 'GET', responseType: 'stream' }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); }

如此,即可解决微博头像因防盗链而无法访问的问题。[]~( ̄▽ ̄)~*