前端配合nginx代理微信头像

本文共有3273个字,关键词:

有个企业微信的应用,最近想要在页面里面展示当前用户的微信头像。

用户的头像是在授权登录后,可以拿到userId,然后服务端再通过获取用户个人信息的接口拿到用户的个人信息,包括头像,存到数据库里。为了不增加额外的存储成本,所以不会将用户的头像再上传到我们自己的存储服务,使用时是直接使用微信头像对应的url从微信服务器中取,得到的微信头像url如下:

http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0

问题

如果我们的前端页面想要直接通过<img src="http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0" crossorigin="anonymous">插入到页面中,会出现跨域问题:

Access to image at 'http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0' from origin 'http://${your-domain}' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决思路

上面说了,为了省成本,我们不会在自己的服务器上再存一份头像的图片,所以拷贝到自己服务器的方案就不考虑了。主要两个方案:

  1. 后端写个接口帮忙获取图片,获取到的图片转为base64返回给前端。
  2. 前端拼接特殊url前缀,通过nginx代理转发到微信图片服务器。

两个方案其实都差不多,我们来看下第二种方案的具体思路。

  1. 前端发起/wechat_image前缀的请求,url上携带原微信头像的路径,如:
/wechat_image?url=http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0&host=wework.qpic.cn
  1. nginx配置拦截 location /wechat_image的代理。

实现步骤

1. 处理url

从接口拿到avatar的url:http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0
我们可以使用new URL来解析一个url,这里以vue代码为例:

<template>
  <img :src="avatarLocal" alt="avatar" class="avatar" crossorigin="anonymous" :onerror="defaultImg" />
</template>

<script>
// 一个默认的占位图像
import iconAvatar from '@/assets/images/avatar.png'
export default {
  data() {
     return {
        avatar: 'http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/0'
        defaultImg: 'this.src="' + iconAvatar + '"' // 如果失败则显示默认图
     }
  },
  computed: {
    avatarLocal () {
      const avatar = this.avatar
      if (!avatar) {
        return iconAvatar
      }
      // 提取url下的域名和最后面的图片大小
      const obj = new URL(avatar)
      const prefix = '/wechat_image'
      // 去掉最后面的/0,改为/100,表示取100px的小图
      const newPath = obj.pathname ? obj.pathname.substr(0, obj.pathname.length - 2) + '/100' : obj.pathname
      // http://www.a.com/xxxx/0 的url会转换为: /wechat_image/xxxx/100?url=http://www.a.com/xxxx/100
      // nginx做/wechat_image拦截,以解决跨域问题
      return `${prefix}${newPath}?url=${obj.origin}${newPath}&host=${obj.hostname}`
    },
  }

}
</script>

2. nginx拦截配置

考虑到微信头像的域名可能有多个,所以我们的代理需要根据url动态改变。
但nginx有个安全限制,就是如果proxy_pass后面是一个参数变量,它会报一个no resolver defined to resolve的错误。因此需要在http节点配置一下:resolver 8.8.8.8 ipv6=off;

http {
  # 解决no resolver defined to resolve错误
  resolver 8.8.8.8 ipv6=off;
 
  server {
     listen 80;
     location /wechat_image {
       proxy_set_header Host "$arg_host";
       proxy_pass $arg_url;
     }
     # 其他的配置...
  }
}

PS: 在nginx中,可以通过$arg_name来获取url后的query参数。

可以看到使用了两个参数$arg_url$arg_host,它们就是上一步在url上拼接的参数,在这个例子里面,他们分别是http://wework.qpic.cn/bizmail/ia7iaXMXfXKuOiapqsvvaibY332FrQpdWPGrbbfGhIeObj2dmXZPJfFLOA/100wework.qpic.cn

本来host参数也是可以在url上截取的,但在nginx中不好处理,所以索性传多一个host参数了。
实践证明, proxy_set_header Host "$arg_host";是必不可少的,不然的话微信图片服务器不会返回真正的图片。

「一键投喂 软糖/蛋糕/布丁/牛奶/冰阔乐!」

fengxianqi

(๑>ڡ<)☆谢谢老板~

使用微信扫描二维码完成支付

版权声明:本文为作者原创,如需转载须联系作者本人同意,未经作者本人同意不得擅自转载。
添加新评论
暂无评论