关于https和http的区别,遇到 RT 的问题,基本概念应该是清楚的,以下说明如何在开发中解决 https下调用http接口。
我解决这个问题,花了很多时间来google,尝试搜索的答案中的各种办法,没有一个能解决,而且亲测失败。
失败的解决方案
-
在html中嵌入 iframe
网上一片的解决方案都是这个,我实在不知道他们是怎么实现的,难道都在瞎扯?iframe嵌入就是通过url引入和iframe下直接编写html代码。通过url引入,url的协议如果是http就会失败,回到问题原点;直接编写iframe下的html,iframe下的html协议默认会使用外层的协议还是https,这就意味着iframe下的html中还会遇到https下请求http的问题,所以从理论上和从实际测试上我都验证了这个办法失败。 -
有一个小伙子的奇葩思路
点击查看原文,这种方案我没有尝试过,但是大概意思就是把http请求中添加上一次https请求的sessionId,即将http请求伪装成https,这方案奇葩,即要先发起一次https请求,然后再伪装http请求,简直就是自己攻击自己。测试的时候玩一玩就好了。但是这个奇葩的例子也给我了一点灵感。
成功的解决方案
- 如果你只是需要发起请求,并且不是需要在当前页面处理返回值,即可用表单请求。
<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,如图
不过既然都已经使用了https了,最好还是不要https和http都混用,只是一些特殊的情况才专门来处理这种问题。