https下调用http

关于https和http的区别,遇到 RT 的问题,基本概念应该是清楚的,以下说明如何在开发中解决 https下调用http接口。

我解决这个问题,花了很多时间来google,尝试搜索的答案中的各种办法,没有一个能解决,而且亲测失败。

失败的解决方案

  1. 在html中嵌入 iframe
    网上一片的解决方案都是这个,我实在不知道他们是怎么实现的,难道都在瞎扯?iframe嵌入就是通过url引入和iframe下直接编写html代码。通过url引入,url的协议如果是http就会失败,回到问题原点;直接编写iframe下的html,iframe下的html协议默认会使用外层的协议还是https,这就意味着iframe下的html中还会遇到https下请求http的问题,所以从理论上和从实际测试上我都验证了这个办法失败。

  2. 有一个小伙子的奇葩思路
    点击查看原文,这种方案我没有尝试过,但是大概意思就是把http请求中添加上一次https请求的sessionId,即将http请求伪装成https,这方案奇葩,即要先发起一次https请求,然后再伪装http请求,简直就是自己攻击自己。测试的时候玩一玩就好了。但是这个奇葩的例子也给我了一点灵感。

成功的解决方案

  1. 如果你只是需要发起请求,并且不是需要在当前页面处理返回值,即可用表单请求。
<form action="http://test.com/action?arg=halo" method="POST">  
    <input type="submit" value="提交">
</form>  

而且不可以阻止默认事件后,又发起异步模拟表单请求,不管你调用jquery的那个方法,如$.Post(), $.Ajax(),等等,都是异步请求,都会被拒绝的。但是可以跳到另一个http的页面处理结果后,又跳回来,这种方法很麻烦,所以肯定不是最好的。

     2. 目前想到的最优方案
        在服务器中定义一个https的接口,这个接口只做重定向,将请求过来的参数不变的重定向到目标http接口中,重定向的过程可以代码实现,可以nginx实现。

以下为测试源码

// https.go
package main  
import (  
    "fmt"
    "log"
    "net/http"
)

func main() {

    fmt.Println("ssl start listen on 9102")
    var cert, key string = "ssl.crt", "ssl.key"

    var url = "http://127.0.0.1:9001/halo?"
    http.HandleFunc("/halo", func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("halo is coming ")
        url += r.URL.RawQuery
        fmt.Println(url)
        http.Redirect(w, r, url, 301)
    })

    http.Handle("/", http.FileServer(http.Dir(".")))
    log.Fatal(http.ListenAndServeTLS(":9102", cert, key, nil))
}
// http.go
package main

import (  
    "fmt"
    "log"
    "net/http"
)

func main() {

    fmt.Println("start listen on 9001")
    http.HandleFunc("/halo", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Write([]byte("halo 9001"))
    })
    log.Fatal(http.ListenAndServe(":9001", nil))
}

详情可以下载源码,前提是自己有ssl证书,并修改host文件,将ssl绑定的域名指定到127.0.0.1,如图 alt

不过既然都已经使用了https了,最好还是不要https和http都混用,只是一些特殊的情况才专门来处理这种问题。