利用nginx变通的解决跨域问题

背景 Link to heading

支付宝商家会员卡业务有两种开卡方式(此处不考虑最新的spi方式)

  • 支付宝app扫投放链接获取会员卡
  • 支付宝小程序通过会员卡参数直接拉起小程序开卡组件

这两个方式在用户填写表单之后都会向指定回调地址中发送一个get请求,并等待成功返回

如果为了兼容上面两种开卡方式,最优选择应该是后端接收到支付宝的get请求后,通过out_string判断是由什么渠道发起的

  • 若浏览器发起,在开卡业务完成后,返回301/302重定向应答,让支付宝app重定向到一个前端页面进行展示
  • 若小程序发起,则返回应答成功的业务报文即可

可是目前我们后端框架暂时无法支持向前端返回301/302这种重定向应答,于是我们暂时只支持了小程序开卡方式

一天支付宝业务人员突然说,他们需要h5扫码方式开会员卡,印刷并张贴在商户门店中,做一些运营活动,很突然,并且当天就要,还要app端跳转到卡包中,于是有了后面的一些操作

解决方案 Link to heading

难点 Link to heading

如上文所说,我们后端并不支持返回301/302应答码,同时也不能导致支付宝小程序发卡失败,那么我们就只有一个方法解决问题,分成两个步骤:

  1. 写一个中转页面,在h5模式下,支付宝app会解析html页面,于是中转页面中不需要有任何的界面,业务也比较简单
  • 获取get请求中的query参数
  • 将参数作为get参数发送给后端
  • 获取请求结果
  • 若应答成功,herf到指定scheme_url
  1. 由于紧急,并且公司内部的一些原因,要在公司主域名下发这个中转页面变得不太现实,于是引发了另外一个问题,跨域

解决 Link to heading

  1. 解决第一个问题非常方便,找了个前端,花几分钟完成了核心代码,一个html文件解决
  2. 第二个问题曾一度陷入死胡同,最后一句闲聊启发了我,为了避免跨域,html只能向自己域发起请求,那么我只需要找个东西在html的域下把get请求转发到后端就可以了,查阅了文档后,直接使用nginx即可做到
      location /ali {
        #判断$query_string中是否有web标识
        if ( $query_string ~* ".*ali_web_redirect.*" ) {
          #有web标识,则跳转到中转页面
            return 301 https://$http_host/redirect/redirect.html?$query_string;
        }
    
        #没有则直接向后端发送请求
        proxy_pass https://www.host.com/api/member/open/alipay/opencard;
      }
    
      location /redirect/ {
        root /opt/www/ali-redirect;
        index index.html index.htm;
      }
      #这个是中转页面发起的请求,此域名收到后,会转发到公司后端
      location ^~ /api/ {
        proxy_pass https://www.host.com;
      }