草庐IT

http - 扩展golang的http包

coder 2024-07-06 原文

我需要扩展 http 包来实现在状态中包含错误描述的非标准响应,即: 400 缺少必需的参数 而不是标准状态描述的 400 Bad request。

这是我的实际实现:

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net/http"
    "net/url"
)

type GatewayHandler int

func main() {
    var gh GatewayHandler

    http.ListenAndServe(":9000", gh)
}

func (gh GatewayHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {

    legacyApiUrl := "http://some-url.com" + req.URL.RequestURI()

    client := &http.Client{}
    request, _ := http.NewRequest(req.Method, legacyApiUrl, nil)
    response, _ := client.Do(request)
    res.Header().Set("Status", response.Status)
    for k, v := range response.Header {
        fmt.Println(k, ": ", v)
        i := ""
        for _, j := range v {
            i += j
        }
        res.Header().Set(k, i)
    }

    res.WriteHeader(response.StatusCode)

    if response.Status != "200 OK" {
        fmt.Println(response.Status)
    }

    result, _ := ioutil.ReadAll(response.Body)
    output := string(result)
    fmt.Println(output)

    io.WriteString(res, output)
}

一般来说,我需要从使用它的其他 URL 转发该状态,并且我需要保持它的兼容性。

非常感谢您。

约瑟夫

最佳答案

您可以使用http.Hijacker 接口(interface)https://golang.org/pkg/net/http/#Hijacker “劫持”(接管)服务器与客户端的 TCP 连接并向其写入自定义响应。这是示例的修改 https://golang.org/pkg/net/http/#example_Hijacker向客户端返回“400 Required parameter is missing”而不是标准的“400 Bad request”响应:

package main

import "net/http"

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        hj, ok := w.(http.Hijacker)
        if !ok {
            http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
            return
        }
        conn, bufrw, err := hj.Hijack()
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        // Don't forget to close the connection:
        defer conn.Close()
        // non-standard HTTP status text and an HTTP header are written;
        // end of the Headers part of the messages is marked by extra \r\n
        bufrw.WriteString("HTTP/1.1 400 Required parameter is missing\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
        // write the body of the HTTP response message
        bufrw.WriteString("400 Required parameter is missing\n")
        bufrw.Flush()
    })
    http.ListenAndServe(":9000", nil)
}

运行此程序并发送 curl 请求会产生所需的响应:

$ curl -i http://localhost:9000/
HTTP/1.1 400 Required parameter is missing
Content-Type: text/html; charset=utf-8

400 Required parameter is missing

扩展它以传播来自旧 API 服务器的其他响应应该很简单。

编辑
根据 HTTP 消息标准 (https://www.rfc-editor.org/rfc/rfc7230#section-3),在示例程序中使用 \r\n\r\n 终止 HTTP 响应的 Headers 部分;为清楚起见,分开的 WriteString 调用 HTTP 响应的 header 和正文。

关于http - 扩展golang的http包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38583672/

有关http - 扩展golang的http包的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  4. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  5. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  6. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

  7. ruby-on-rails - Heroku 吃掉了我的自定义 HTTP header - 2

    我正在使用Heroku(heroku.com)来部署我的Rails应用程序,并且正在构建一个iPhone客户端来与之交互。我的目的是将手机的唯一设备标识符作为HTTPheader传递给应用程序以进行身份​​验证。当我在本地测试时,我的header通过得很好,但在Heroku上它似乎去掉了我的自定义header。我用ruby​​脚本验证:url=URI.parse('http://#{myapp}.heroku.com/')#url=URI.parse('http://localhost:3000/')req=Net::HTTP::Post.new(url.path)#boguspara

  8. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  9. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  10. ruby - HTTP 请求中的用户代理,Ruby - 2

    我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

随机推荐