使用GO 程序指定IP地址访问 http/https 地址 类似curl --resolve XXXIP:PortYYY


需求,使用GO 程序指定IP地址访问 http/https 地址

传入参数:

ipAddr // ipv4地址 string值
serviceUrl // url地址 string值
hostContainPort // Host Header 是否带url的端口 bool值

返回值:

responseCode // http状态码 int类型, 
Host // request 请求Host Header string类型

 

// HttpTestOnceHostBindIp http请求测试,指定目的IP地址
func  HttpTestOnceHostBindIp(ipAddr, serviceUrl string, hostContainPort bool) (responseCode int, Host string) {

    //异常处理
    defer func() {
        //捕获异常
        err := recover()
        if err != nil { //条件判断,是否存在异常
            //存在异常,抛出异常
            //fmt.Println(err)
            fmt.println("http请求serviceUrl 一次出错:%v", err)
            responseCode = -8888
        }
    }()
    responseCode = -8888
    urlObj, err := url.Parse(serviceUrl)
    if err != nil {
        fmt.println("url.Parse(serviceUrl) Error: %v", err)
    }
    // 获取传入URL的端口是什么,有指定获取指定的,没有指定根据http/https协议默认端口传入
    var port string
    // 1. 有指定端口
    if strings.Contains(urlObj.Host, ":") {
        hostSlice := strings.Split(urlObj.Host, ":")
        if len(hostSlice) >= 1 {
            port = hostSlice[1]
        }
    } else {
        // 2. 没有指定端口 使用默认端口
        if urlObj.Scheme == "https" {
            port = "443"
        } else if urlObj.Scheme == "http" {
            port = "80"
        }
    }
    //fmt.Println("urlObj.Host: ", urlObj.Host)     // 根据url获取Host
    //fmt.Println("urlObj.Scheme: ", urlObj.Scheme) // http请求协议,http或者https
    //port := "80"
    request, err := http.NewRequest("GET", urlObj.String(), bytes.NewBuffer([]byte{}))

    // 规则要求带端口的url如果Host不包含Port就把 HTTP请求的Host头里的:端口号去掉
    if !hostContainPort {
        if strings.Contains(urlObj.Host, ":") {
            hostSlice := strings.Split(urlObj.Host, ":")
            if len(hostSlice) >= 1 {
                request.Host = hostSlice[0]
            }
        }
    }

    defer request.Body.Close() //
    var response *http.Response

    // 一、 绑定固定的IP
    // 1. 先准备一个Dialer对象
    dialer := &net.Dialer{
        Timeout:   7 * time.Second,
        KeepAlive: 30 * time.Second,
    }
    transport := &http.Transport{
        // 2. 插入特别的改写条件,然后继续利用原先的DialContext逻辑
        DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
            addr = ipAddr + ":" + port
            //if addr == "api.lewinblog.com:80" {
            //    addr = "127.0.0.1:80"
            //}
            return dialer.DialContext(ctx, network, addr)
        },
    }

    // 客户端禁止重定向
    client := &http.Client{
        CheckRedirect: noRedirect, //http客户端禁止重定向
        Transport:     transport,
    }
    //response, err = http.DefaultClient.Do(request)
    response, err = client.Do(request)
    if err != nil {
        fmt.println("client.Do(request) Error:%v", err)
    }
    if response != nil {
        responseCode = response.StatusCode

        if response.Body != nil {
            err = response.Body.Close() //必须关闭否则自动打开的goroutine无法关闭
            if err != nil {
                fmt.println("response.Body.Close()Error:%v", err)
            }
        }
        fmt.println("serviceUrl %v ip: %s response Code: %v", serviceUrl, ipAddr, responseCode)
    }
    Host = request.Host
    return
}

 

posted on 2023-09-07 16:13  zhangmingda  阅读(304)  评论(0编辑  收藏  举报

导航