GOLANG实现的HTTP转HTTPS的代理

winlin 发表了文章 • 0 个评论 • 179 次浏览 • 2017-10-13 12:17 • 来自相关话题

有时候需要将后端的HTTP服务,转成HTTPS,可以用一个代理。

Reamark: 如果是GOLANG的后端服务,可以直接用库go-oryx-lib/https

查看全部

有时候需要将后端的HTTP服务,转成HTTPS,可以用一个代理。



Reamark: 如果是GOLANG的后端服务,可以直接用库go-oryx-lib/https



这个代理支持自签名的证书,也支持letsencrypt的证书。



Remark: Letsencrypt只支持少量域名的情况,比如自己的网站,它会有请求次数限制,另外CA是letsencrypt的,商业用户不适合用。



我们有个HTTP API, SRS Version:


{
"code": 0,
"server": 12504,
"data": {
"major": 2,
"minor": 0,
"revision": 243,
"version": "2.0.243"
}
}

下面演示实现HTTPS的代理。


Self-sign Certificate


自签名证书可以用在测试中,先生成私钥server.key和证书server.crt


openssl genrsa -out server.key 2048 &&
openssl req -new -x509 -key server.key -out server.crt -days 365


Remark: 生成证书时会有很多提问,直接回车就好了。还可以参考openssl的文档,直接在命令行设置这些参数。



生成私钥和证书后,下载HTTPS代理:


go get github.com/ossrs/go-oryx/httpx-static


Remark: GOLANG的设置请参考GO环境配置


Note: 详细参数可以直接运行httpx-static程序不带参数,会显示help。



启动服务,代理到SRS Version:


sudo $GOPATH/bin/httpx-static -http 80 -https 443 \
-proxy http://ossrs.net:1985/api/v1/versions \
-ssc server.crt -ssk server.key

访问本机HTTP和HTTPS就可以:



  1. HTTP: http://localhost/api/v1/versions

  2. HTTPS: https://localhost/api/v1/versions



Remark: 浏览器访问自签名证书时,可能会提示不安全,选择高级然后继续浏览就可以了。



LetsEncrypt Certificate


可以使用letsencrypt签名的证书,在浏览器中会显示合法的绿色,不会提示有错误。参考:ossrs.net


ossrs.net也是使用httpx-static,参数如下:


sudo $GOPATH/bin/httpx-static -http 80 -https 443 \
-lets=true -domains ossrs.net


Remark: 注意在局域网的机器无法使用,因为ACME会有反向验证,也就是你的服务器得能在公网访问到。



Advance Proxy


如果需要代理所有的API怎么办呢?直接指定父目录就好,如果指定/则代理所有的请求。例如:


下面的命令,代理所有的/api请求:


sudo $GOPATH/bin/httpx-static -http 80 -https 443 \
-proxy http://ossrs.net:1985/api \
-ssc server.crt -ssk server.key

下面的命令,代理所有的请求,相当于做了镜像:


sudo $GOPATH/bin/httpx-static -http 80 -https 443 \
-proxy http://ossrs.net/ \
-ssc server.crt -ssk server.key

其他的参数请参考httpx-static的参数。

感觉 sync.Pool 很容易用错

tpkeeper 回复了问题 • 5 人关注 • 5 个回复 • 673 次浏览 • 2017-10-13 10:30 • 来自相关话题

是否可用openresty作为grpc的路由(更新:目前看我觉得不行)

kevin 回复了问题 • 4 人关注 • 2 个回复 • 362 次浏览 • 2017-09-29 17:52 • 来自相关话题

关于GO反射的简单定律

gundamzaku 发表了文章 • 0 个评论 • 204 次浏览 • 2017-09-22 12:52 • 来自相关话题

自己待业在家,花了两天时间翻译出来的。。
虽然有些不完美,不过也算是费心之作了。
现在分享出来以供学习,
查看全部

自己待业在家,花了两天时间翻译出来的。。

虽然有些不完美,不过也算是费心之作了。

现在分享出来以供学习,

https://github.com/gundamzaku/golang_study_note/blob/master/%E5%8F%8D%E5%B0%84%E7%9A%84%E7%AE%80%E5%8D%95%E5%AE%9A%E5%BE%8B.md


当然,更详细的反射学习也有,不过是自己看代码整理出来的。花了不少的工作

https://github.com/gundamzaku/golang_study_note/tree/master/%E5%8F%8D%E5%B0%84reflect


有兴趣学习的可以看看,这几块全是关于反射的内容,也顺便能指出有问题的地方:)

大家都用什么web框架

songtianyi 回复了问题 • 20 人关注 • 20 个回复 • 3324 次浏览 • 2017-09-20 16:21 • 来自相关话题

关于指针的取值的小白问题

javasgl 回复了问题 • 3 人关注 • 3 个回复 • 303 次浏览 • 2017-09-13 08:36 • 来自相关话题

欢迎加入安徽Golang交流群

回复

ecofast 发起了问题 • 1 人关注 • 0 个回复 • 359 次浏览 • 2017-08-28 15:16 • 来自相关话题

golang网站流量统计 中 消息队列+多线程+orm+sql 存库

alalmn 发表了文章 • 1 个评论 • 344 次浏览 • 2017-08-26 11:47 • 来自相关话题

package main

//golang网站流量统计  中  消息队列+多线程+orm+sql 存库
//QQ:29295842  欢迎... 			查看全部
					
package main

//golang网站流量统计 中 消息队列+多线程+orm+sql 存库
//QQ:29295842 欢迎技术交流
//http://blog.csdn.net/webxscan
//里面包含了数据库 整个工程GIT有下载
//github https://github.com/webxscan/golang_tj2
//bee api apiPro -driver=mysql -conn="root:29295842@tcp(127.0.0.1:3306)/seo?charset=utf8"
import (
"fmt"
"sync"

"encoding/json"
"log"
// "strconv"
"strings"
"time"

"net/url"

"github.com/astaxie/beego"
"github.com/astaxie/beego/session"

"github.com/Damnever/goqueue"
"github.com/astaxie/beego/orm"
_ "github.com/go-sql-driver/mysql"
)

//==========================
var (
Url_queue = goqueue.New(300000)
wg = &sync.WaitGroup{}
)

func Queue_size(queue *goqueue.Queue) int { //数量
return queue.Size()
}

func Queue_get(queue *goqueue.Queue) string { //获取数据
if !queue.IsEmpty() {
val, err := queue.Get(5)
if err != nil {
return ""
} else {
wg.Wait()
return fmt.Sprintf("%v", val)
}
}
return ""
}

func Queue_put(queue *goqueue.Queue, data string) { //写入数据
defer wg.Done()
queue.PutNoWait(data)
wg.Add(1)
}

//==========================

type Ip struct {
Id int // `orm:"column(id)"`
Time int `orm:"column(time)" description:"请求时间"`
Ip string `orm:"column(ip);size(100)" description:"请求IP"`
Www_host string `orm:"column(www_host);size(100)" description:"请求域名"`
Www_url string `orm:"column(www_url);size(100);null" description:"请求路径"`
Referer string `orm:"column(Referer);size(100);null" description:"来路"`
Method string `orm:"column(Method);size(100);null" description:"请求方式"`
UserAgent string `orm:"column(User_Agent);size(200);null" description:"请求头"`
Cs string `orm:"column(cs);size(100);null" description:"请求次数"`
}

func init() {
maxIdle := 30 //设置最大空闲连接
maxConn := 30 //设置最大数据库连接
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterModel(new(Ip))
orm.RegisterDataBase("default", "mysql", "root:316118740@tcp(127.0.0.1:3306)/seo?charset=utf8", maxIdle, maxConn)
}

func add_sql() {
i := Queue_size(Url_queue)
if i == 0 {
return
}
for index := 0; index < i; index++ {
sql_data := Queue_get(Url_queue) //获取数据
if sql_data == "" {
continue //跳过
}
//================
//ORM 方法1
// orm.Debug = true
// o := orm.NewOrm()
// o.Using("default") //指定数据库
// user := Ip{Time: int(time_Unix), Ip: "ddddddd"}
// id, err := o.Insert(&user) //添加
// // o.Delete(&user) //删除
// // o.Update(&user) //更新
// if err == nil {
// fmt.Println(id)
// }

//ORM SQL语句法
// orm.Debug = true
// o := orm.NewOrm()
// o.Using("default") //指定数据库
// sSql := fmt.Sprintf("insert into ip (time, ip) values(%d,'%s')", int(time_Unix), "ddddddd")
//ORM SQL语句法
orm.Debug = true
orm_sql := orm.NewOrm()
orm_sql.Using("default") //指定数据库
_, err := orm_sql.Raw(sql_data).Exec()
if err != nil {
fmt.Println("插入出错")
}
//================
}
return
}

//===================
var globalSessions *session.Manager

type Iindex struct {
beego.Controller
}

func init() {
config := fmt.Sprintf(`{"cookieName":"gosessionid","gclifetime":%d,"enableSetCookie":true}`, 3600*24) //
conf := new(session.ManagerConfig)
if err := json.Unmarshal([]byte(config), conf); err != nil {
log.Fatal("json decode error", err)
}
globalSessions, _ = session.NewManager("memory", conf)
go globalSessions.GC()
}

//网站访问计数器
func (this *Iindex) Count() {
path_url := this.Ctx.Request.URL.String()
fmt.Println("get url:", path_url)
if path_url == "/favicon.ico" { //忽略此路由地址请求
this.Ctx.WriteString("")
this.Ctx.ResponseWriter.Header().Set("Content-Type", "text/html")
return
}

//this.Ctx.Request //这里面有大家所需要一切客户信息
//fmt.Printf("===%v===\n", this.Ctx.Request)

time_Unix := time.Now().Unix()
Client_Host := this.Ctx.Request.Host //访问域名
Client_Method := this.Ctx.Request.Method //请求方式
Client_User_Agent := this.Ctx.Request.Header.Get("User-Agent") //请求头
Client_IP := this.Ctx.Request.Header.Get("Remote_addr") //客户端IP
Client_Referer := this.Ctx.Request.Header.Get("Referer") //来源
if len(Client_IP) <= 7 {
Client_IP = this.Ctx.Request.RemoteAddr //获取客户端IP
}
if strings.Contains(Client_IP, ":") {
ip_boolA, ip_dataA := For_IP(string(Client_IP)) //获取IP
if ip_boolA {
Client_IP = ip_dataA
}
}

this.Ctx.ResponseWriter.Header().Set("Content-Type", "text/html")
this.Ctx.WriteString("golang网站流量统计 中 消息队列+多线程+orm+sql 存库</br>\n")
this.Ctx.WriteString("QQ:29295842</br>\n")

this.Ctx.WriteString(fmt.Sprintf("=====客户端IP:%v======</br>\n", Client_IP))
this.Ctx.WriteString(fmt.Sprintf("=====访问域名:%v======</br>\n", Client_Host))
this.Ctx.WriteString(fmt.Sprintf("=====请求路径:%v======</br>\n", path_url))
this.Ctx.WriteString(fmt.Sprintf("=====来源来路:%v======</br>\n", Client_Referer))
this.Ctx.WriteString(fmt.Sprintf("=====请求方式:%v======</br>\n", Client_Method))
this.Ctx.WriteString(fmt.Sprintf("=====请求头:%v======</br>\n", Client_User_Agent))
this.Ctx.WriteString(fmt.Sprintf("=====访问次数:%v======</br>\n", this.Cookie_session()))
//后面就是数据存贮 可以多种模式
//消息队列+多线程+orm+sql 存库
Client_User_Agent = strings.Replace(Client_User_Agent, ",", "_", -1)
Client_User_Agent = strings.Replace(Client_User_Agent, ",", "_", -1)
Client_User_Agent = strings.Replace(Client_User_Agent, "'", "_", -1)
Client_User_Agent = strings.Replace(Client_User_Agent, "\"", "_", -1)
Client_User_Agent = strings.Replace(Client_User_Agent, "/", "_", -1)
//Client_User_Agent = strings.Replace(Client_User_Agent, ";", "_", -1)
//Client_User_Agent = strings.Replace(Client_User_Agent, " ", "_", -1)
resUri, pErr := url.Parse(path_url) //转义URL地址
if pErr != nil {
path_url = "/"
} else {
path_url = resUri.Path
}

data_sql := fmt.Sprintf("insert into ip (time,ip,www_host,www_url,Referer,Method,User_Agent,cs) values(%d,'%s','%s','%s','%s','%s','%s','%d')",
int(time_Unix), Client_IP, Client_Host, path_url, Client_Referer, Client_Method, Client_User_Agent, this.Cookie_session())

Queue_put(Url_queue, data_sql) //写入队列

return
}

func For_IP(valuex string) (bool, string) {
data_list := strings.Split(valuex, ":")
if len(data_list) >= 2 {
return true, data_list[0]
}
return false, ""
}

func (this *Iindex) Cookie_session() int { //id统计 PV 这样统计只能针对单个浏览器有效
pv := 0
//=====================
//Cookie 统计法
// cook := this.Ctx.GetCookie("countnum") //获取Cookie
// if cook == "" {
// this.Ctx.SetCookie("countnum", "1", "/")
// pv = 1
// } else {
// xx, err := strconv.Atoi(cook)
// if err == nil {
// pv = xx + 1
// this.Ctx.SetCookie("countnum", strconv.Itoa(pv), "/")
// } else {
// //this.Ctx.SetCookie("countnum", "1", "/")
// pv = 0
// }
// }
// return pv
//=====================
//session 统计法
sess, _ := globalSessions.SessionStart(this.Ctx.ResponseWriter, this.Ctx.Request)
ct := sess.Get("countnum")
if ct == nil {
sess.Set("countnum", 1)
pv = 1
} else {
pv = ct.(int) + 1
sess.Set("countnum", pv)
}
return pv
}

//===================

func main() {

fmt.Println("----------------")

go func() { //多线程任务
for { //死循环
time.Sleep(time.Second * 1)
add_sql() //定时更新器
}
}()
go func() { //
for { //死循环
time.Sleep(time.Second * 5)
add_sql() //定时更新器
}
}()
go func() { //
for { //死循环
time.Sleep(time.Second * 10)
add_sql() //定时更新器
}
}()

//===========================================
beego.BConfig.Listen.ServerTimeOut = 10 //设置 HTTP 的超时时间,默认是 0,不超时。
//beego.BConfig.Listen.EnableHTTP = true //是否启用 HTTP 监听,默认是 true。

beego.BConfig.Listen.HTTPPort = 1000 //应用监听端口,默认为 8080。

//beego.SetLogger("file", `{"filename":"logs/admin.log","maxlines":10000}`)
// beego.BConfig.EnableErrorsShow = false //是否显示系统错误信息,默认为 true。
// //是否将错误信息进行渲染,默认值为 true,即出错会提示友好的出错页面,对于 API 类型的应用可能需要将该选项设置为 false 以阻止在 dev 模式下不必要的模板渲染信息返回
// beego.BConfig.EnableErrorsRender = false
// //运行模式,可选值为 prod, dev 或者 test. 默认是 dev, 为开发模式
// // beego.BConfig.RunMode = "prod"
// //运行模式,可选值为 prod, dev 或者 test. 默认是 dev, 为开发模式
// beego.BConfig.RunMode = "test"

beego.BConfig.AppName = "斗转星移" //应用名称,默认是 beego。通过 bee new 创建的是创建的项目名。
beego.BConfig.ServerName = "QQ:29295842" //beego 服务器默认在请求的时候输出 server 为 beego。

beego.BConfig.WebConfig.Session.SessionName = "sessionID" //存在客户端的 cookie 名称,默认值是 beegosessionID。
beego.BConfig.WebConfig.Session.SessionGCMaxLifetime = 3600 * 24 //session 过期时间,默认值是 3600 秒。
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 //session 默认存在客户端的 cookie 的时间,默认值是 3600 秒。

//beego.BConfig.WebConfig.Session.SessionDomain = "" //session cookie 存储域名, 默认空。
//beego.BConfig.WebConfig.ViewsPath = "admin" //模板路径,默认值是 views。

beego.Router("/*", &Iindex{}, "*:Count")
go beego.Run()
//=============================================
for { //死循环
time.Sleep(10 * time.Second)
}

//make一个chan用于阻塞主线程,避免程序退出
// blockMainRoutine := make(chan bool)
// <-blockMainRoutine
//===========================================

// Queue_put(Url_file_queue, "xxxxxxxxxxxxxxxxxxxxxxxxx") //写入数据

// fmt.Printf("===%v===\n", Queue_get(Url_file_queue))

}


前两天在 Leetcode 做题时发现一个问题,特来请教一下。

katherine 回复了问题 • 6 人关注 • 3 个回复 • 896 次浏览 • 2017-08-25 19:06 • 来自相关话题

被学校suspension该怎么办?

ahjkhkjf 发表了文章 • 1 个评论 • 196 次浏览 • 2017-08-25 13:13 • 来自相关话题

I-20被中止/F1签证续签不过/学业警告/劝退/改GPA改成绩则添加扣Q 1069783685 在美国留学的申请路上GPA决定着一个学生的命运 1、在申请期间,它与标准化考试托福/GRE/GMAT有着同等重要的作用;   2、到美国留学期间,如果GPA... 查看全部

I-20被中止/F1签证续签不过/学业警告/劝退/改GPA改成绩则添加扣Q 1069783685
在美国留学的申请路上GPA决定着一个学生的命运
1、在申请期间,它与标准化考试托福/GRE/GMAT有着同等重要的作用;
  2、到美国留学期间,如果GPA达不到学校要求,会面临退学的风险;
  3、在找工作时,雇佣公司对GPA的侧重,远超过于毕业院校的名气!
  


美国留学条件的GPA计算方式 美国与中国存在很大不同
GPA全称Grade Point Average,俗称绩点,是由学生提交长时间(3到4年)的成绩单进行加权计算得来。其具体计算方法有很多种,但是比较普遍的一种是:成绩为A时记作4分,B记做3分,C为2分,D为1分,E(不及格)则为0分。A-一般记做3.6-3.8分,B+则会被记做3.2-3.4分,以此类推。在记录每科的成绩之后,根据学分加权平均得出GPA.如当GPA为3.4时,则表示平均成绩基本在85分以上。
  而在美国,GPA的评估源自数年的连贯考核,这就要求学生在考试和随堂测验取得高分之外,还要保持出勤率、长期优异的课堂表现和按时递交作业与学习报告。绩点的上涨绝非一朝一夕之功,更不是一次大考就可扭转的。这与中国有着很大的不同!
  
美国留学条件GPA不达标,签证和学习资格不保
  国际学生的F1签证合法性与GPA直接挂钩。本科GPA不足2.0,研究生不足3.0的学生会被勒令退学!这样的事情非常多,举一个例子,有一名本科学习生物的同学在进入药学院攻读研究生时,因为专业转换和英语写作技巧匮乏,即使自己万分努力成绩依然不理想,GPA不满3分,随即便被学校告知,如果不能提高成绩将被劝退。万幸的是,经导师推荐该同学转到生物系学习,回归本专业的他虽然逃脱了失学的危险,但也要重读研一,浪费了不少时间和学费。但这就是国外大学所谓“宽进严出”的机制。
  
美国留学条件GPA是升学就业敲门砖
  3.0以下的GPA基本让留学生与优秀大学失之交臂。根据官方公布的已录取学生数据,麻省大学阿姆赫斯特校区所录取本科学生的平均GPA达到3.73.可见,想要进入好的学校,没有过硬的GPA会非常艰难。除了升学,美国企业在招聘时,都要求申请人填写上一个教育项目里取得的GPA,这在中国职场并不常见。美国企业习惯根据在校成绩来衡量学生的学习态度和专业技能。由此看来,GPA分数的高低对学生的未来发展至关重要。
  一些到美国留学的学生为了获得更高的GPA费尽心思,甚至放弃一些不易拿A的课程,转而选修相对简单的科目,此举有投机取巧之嫌。要知道在申请美国大学时,所修课程的难度也是招生官要考查的因素之一。其实,一个近乎满分的GPA并不代表最高竞争力,GPA也只是众多参数中的一个。
  即使GPA不占优势的学生也可以通过其他方面给自己加分,如论文、社团活动、实习经历、竞赛证书、老师推荐信等等。不过对于每一个留学生来说,维持高GPA是留学成功的根本,对待GPA的心态是万万不能放松的。
  
美国留学条件GPA是一切奖项荣誉的门槛
  在美国,大部分学校的奖学金和荣誉称号对GPA都有不同程度的门槛要求,没有3.4或是3.5的GPA,国际学生申请奖学金是基本没有希望的。而毕业时,达到一定GPA的学生才有被授予荣誉毕业生称号的可能。还有些荣誉奖项意义重大,比如著名的“phi beta kappa society” (美国优等生联谊会),会员包括17位美国总统在内的各类社会名流,该社团每年会从全美顶尖大学招聘优秀学生,GPA达3.75以上才有机会入选。一旦通过选拔加入这个社团,已经证明了自己出色的能力,一脚迈进了成功的大门。
  
美国留学条件GAP是加入学术团体,研究项目的必备资格
  进入美国大学以后,如需报名参加学术团体、项目研究或是申请助教岗位,学校对GPA也有相应限制。有这样一个例子:麻省大学波士顿校区的G同学长期辅导美国同学学习中文,因此中文系主任非常想聘请G同学担任助教。可惜G同学由于第一学年GPA不足3.0,不满足学校聘请助教的要求,因此即使中文系主任极力推荐,G同学也只能无奈错失良机

不同语言session能否共享?比如PHP和go,谁做过类似的东西

tupunco 回复了问题 • 7 人关注 • 7 个回复 • 1188 次浏览 • 2017-08-22 08:28 • 来自相关话题

变量可以和import的包重名了?

回复

localvar 发起了问题 • 2 人关注 • 0 个回复 • 299 次浏览 • 2017-08-18 22:04 • 来自相关话题

golang有没有好的开源游戏框架

cye 回复了问题 • 22 人关注 • 12 个回复 • 7272 次浏览 • 2017-08-16 17:23 • 来自相关话题

go的beego框架在不使用orm的情况下怎么操作数据库?

jsharkc 回复了问题 • 4 人关注 • 3 个回复 • 432 次浏览 • 2017-08-14 10:53 • 来自相关话题

golang sync mutex

kodango 回复了问题 • 4 人关注 • 4 个回复 • 414 次浏览 • 2017-08-09 11:21 • 来自相关话题