如何本地调试有IP限制的三方接口

经常碰到三方接口有ip限制,需要将我们这边的ip地址加入对方的白名单才能进行访问测试。
这就给测试增加了难度,有以下原因

  • 本地 ip 是动态的
  • 不允许将本地 ip 提供给三方

以前每次测试都提交到测试环境,然后测试,改动多的话就会特别麻烦。
后面查找有没有方法本地就可以测试,发现http代理可以实现,配合guzzle的代理使用特别方便。

    resolver x.x.x.x;       #指定DNS服务器IP地址(需替换成自己的)  
    location / {  
        proxy_pass https://$http_host$request_uri;     #设定代理服务器的协议和地址 
        proxy_set_header HOST $http_host;
        proxy_buffers 256 4k;
        proxy_max_temp_file_size 0k; 
        proxy_connect_timeout 30;
        proxy_send_timeout 60;
        proxy_read_timeout 60;
        proxy_next_upstream error timeout invalid_header http_502;
    }

但是这个有几个问题

  • 没有防护,所有人都能使用此代理(已经看到很多访问了:()
  • 目前没法通过域名设置代理,只能通过 ip 加端口,所以代理都是 127.0.0.1:8080 这种。
  • 没法直接访问 https 请求,需要将改成 http 在 proxy_pass 指定协议 https (每次设置都很麻烦)

大家有没有“优雅”的方式调试这种三方 ip 限制的接口?

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 17

最近我也遇到类似的情况。我这边是这样,第三方服务的api会限制ip,而且只能填一个。我现在的做法是第三方服务的平台中填写服务器A的ip,然后在服务器A上写一个转发程序,本地服务器B或者其他服务器C调用服务器A上的转发程序,服务器A再把接收到的数据提交到第三方服务。

1年前 评论
cxcsz (楼主) 1年前
mofung (作者) 1年前
cxcsz (楼主) 1年前
mofung (作者) 1年前
cxcsz (楼主) 1年前
cxcsz (楼主) 1年前
sanders

:sweat_smile: 标准流程应该是自己做 mock 吧。

1年前 评论
cxcsz (楼主) 1年前
Imuyu 1年前
sanders (作者) 1年前

A 做个代理服务器,然后其他服务器使用 socks 访问

1年前 评论

找台云服务器,搭建个nginx转发一下,第三方平台配置云服务器ip。

location /xxxx/ {
      access_by_lua '
        ngx.req.set_uri_args(params)   验证等
      ';
      proxy_pass http://原始网址;
      proxy_cache cache_one;
      proxy_cache_valid 200 304 302 90s;
      proxy_cache_bypass $arg_nocache;
   }
}
1年前 评论
yyy123456 1年前
skarner

白名单加你们自己公司的一台机器的IP(比如测试环境机器的公网IP)

然后再在这台机器上转个代理

本地请求通过这台机器的代理去请求即可

1年前 评论
GDDD

workerman很快就能搭建http代理服务器

1年前 评论

感谢大家的反馈,测试过 nginx 转发 http 和 https,一直没有成功。原来一直没有找到合适的解决方案就搁置了,后来是使用 golang 写了个简单的代理解决的。只能感叹 chatgpt 的强大。

package main

import (
    "encoding/base64"
    "io"
    "log"
    "net"
    "net/http"
    "strings"
)

// 用户认证信息
var (
    proxyUsername = "user"
    proxyPassword = "password"
)

func handleTunneling(w http.ResponseWriter, r *http.Request) {
    if !checkProxyAuth(r) {
        w.Header().Set("Proxy-Authenticate", `Basic realm="Proxy Authentication"`)
        http.Error(w, "Proxy Authentication Required", http.StatusProxyAuthRequired)
        return
    }

    destConn, err := net.Dial("tcp", r.Host)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    w.WriteHeader(http.StatusOK)
    hijacker, ok := w.(http.Hijacker)
    if !ok {
        http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
        return
    }
    clientConn, _, err := hijacker.Hijack()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    go transfer(destConn, clientConn)
    go transfer(clientConn, destConn)
}

func handleHTTP(w http.ResponseWriter, req *http.Request) {
    if !checkProxyAuth(req) {
        w.Header().Set("Proxy-Authenticate", `Basic realm="Proxy Authentication"`)
        http.Error(w, "Proxy Authentication Required", http.StatusProxyAuthRequired)
        return
    }

    // 修改请求的URL
    transport := http.DefaultTransport
    outReq := new(http.Request)
    *outReq = *req // 复制请求

    if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
        http.Error(w, "Unsupported scheme", http.StatusBadRequest)
        return
    }

    // 发送请求
    res, err := transport.RoundTrip(outReq)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadGateway)
        return
    }
    defer res.Body.Close()

    // 复制响应头
    for key, value := range res.Header {
        w.Header()[key] = value
    }
    w.WriteHeader(res.StatusCode)

    // 复制响应体
    io.Copy(w, res.Body)
}

func checkProxyAuth(r *http.Request) bool {
    // 检查代理授权头
    auth := r.Header.Get("Proxy-Authorization")
    if auth == "" {
        return false
    }

    // 解码认证信息
    creds, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
    if err != nil {
        return false
    }

    // 验证用户名和密码
    if string(creds) != proxyUsername+":"+proxyPassword {
        return false
    }

    return true
}

func transfer(destination io.WriteCloser, source io.ReadCloser) {
    defer destination.Close()
    defer source.Close()
    io.Copy(destination, source)
}

func main() {
    server := &http.Server{
        Addr: ":8080",
        Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if r.Method == http.MethodConnect {
                handleTunneling(w, r)
            } else {
                // 处理HTTP请求
                handleHTTP(w, r)
            }
        }),
    }

    log.Fatal(server.ListenAndServe())
}

该代码实现了http 和 https 转发;添加了用户认证,防止别人来调用(自己的服务器差点被打趴下了)。 guzzle 调用示例

$config = [
    'proxy' =>  'http://user:password@xx.xx.xx.xx:8080'
];
$client = new \GuzzleHttp\Client($config);
$res = $client->get("https://httpbin.org/get");
$res = $client->get("http://httpbin.org/get");
8个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!