{"id":13459807,"url":"https://github.com/elazarl/goproxy","last_synced_at":"2026-02-13T00:22:13.149Z","repository":{"id":2802149,"uuid":"3802828","full_name":"elazarl/goproxy","owner":"elazarl","description":"An HTTP proxy library for Go","archived":false,"fork":false,"pushed_at":"2025-04-07T22:47:10.000Z","size":597,"stargazers_count":6324,"open_issues_count":80,"forks_count":1135,"subscribers_count":150,"default_branch":"master","last_synced_at":"2025-05-05T14:16:16.524Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elazarl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-03-22T22:05:00.000Z","updated_at":"2025-05-01T05:45:14.000Z","dependencies_parsed_at":"2023-07-05T20:46:18.066Z","dependency_job_id":"c199d379-8d6f-4d54-846d-fe7f7b72a78f","html_url":"https://github.com/elazarl/goproxy","commit_stats":{"total_commits":262,"total_committers":87,"mean_commits":"3.0114942528735633","dds":0.5687022900763359,"last_synced_commit":"6741dbfc16a13e515d5f2b485eb4be24692e54de"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elazarl%2Fgoproxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elazarl%2Fgoproxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elazarl%2Fgoproxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elazarl%2Fgoproxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elazarl","download_url":"https://codeload.github.com/elazarl/goproxy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253774593,"owners_count":21962199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T10:00:29.509Z","updated_at":"2026-02-13T00:22:13.131Z","avatar_url":"https://github.com/elazarl.png","language":"Go","readme":"# GoProxy\n\n![Status](https://github.com/elazarl/goproxy/workflows/Go/badge.svg)\n[![GoDoc](https://pkg.go.dev/badge/github.com/elazarl/goproxy)](https://pkg.go.dev/github.com/elazarl/goproxy)\n[![Go Report](https://goreportcard.com/badge/github.com/elazarl/goproxy)](https://goreportcard.com/report/github.com/elazarl/goproxy)\n[![BSD-3 License](https://img.shields.io/badge/License-BSD%203--Clause-orange.svg)](https://opensource.org/licenses/BSD-3-Clause)\n[![Pull Requests](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)\n[![Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go?tab=readme-ov-file#networking)\n\nGoProxy is a library to create a `customized` HTTP/HTTPS `proxy server` using\nGo (aka Golang), with several configurable settings available.\nThe target of this project is to offer an `optimized` proxy server, usable with\nreasonable amount of traffic, yet `customizable` and `programmable`.\n\nThe proxy itself is simply a `net/http` handler, so you can add multiple\nmiddlewares (panic recover, logging, compression, etc.) over it. It can be\neasily integrated with any other HTTP network library.\n\nIn order to use goproxy, one should set their browser (or any other client)\nto use goproxy as an HTTP proxy.\nHere is how you do that in [Chrome](https://www.wikihow.com/Connect-to-a-Proxy-Server)\nand in [Firefox](http://www.wikihow.com/Enter-Proxy-Settings-in-Firefox).\nIf you decide to start with the `base` example, the URL you should use as\nproxy is `localhost:8080`, which is the default one in our example.\nYou also have to [trust](https://github.com/elazarl/goproxy/blob/master/examples/customca/README.md)\nthe proxy CA certificate, to avoid any certificate issue in the clients.\n\n\u003e [✈️ Telegram Group](https://telegram.me/goproxygroup)\n\u003e\n\u003e [🎁 Become a Sponsor](https://opencollective.com/goproxy)\n\n## Features\n- Perform certain actions only on `specific hosts`,  with a single equality comparison or with regex evaluation\n- Manipulate `requests` and `responses` before sending them to the browser\n- Use a `custom http.Transport` to perform requests to the target server\n- You can specify a `MITM certificates cache`, to reuse them later for other requests to the same host, thus saving CPU. Not enabled by default, but you should use it in production!\n- Redirect normal HTTP traffic to a `custom handler`, when the target is a `relative path` (e.g. `/ping`)\n- You can choose the logger to use, by implementing the `Logger` interface\n- You can `disable` the HTTP request headers `canonicalization`, by setting `PreventCanonicalization` to true\n\n## Proxy modes\n1. Regular HTTP proxy\n2. HTTPS through CONNECT\n3. HTTPS MITM (\"Man in the Middle\") proxy server, in which the server generate TLS certificates to parse request/response data and perform actions on them\n4. \"Hijacked\" proxy connection, where the configured handler can access the raw net.Conn data\n\n## Sponsors\nDoes your company use GoProxy? Help us keep the project maintained and healthy!\nSupporting GoProxy allows us to dedicate more time to bug fixes and new features.\nIn exchange, if you choose a Gold Supporter or Enterprise plan, we'll proudly display your company logo here.\n\n\u003e [Become a Sponsor](https://opencollective.com/goproxy)\n\n[![Gold Supporters](https://opencollective.com/goproxy/tiers/gold-sponsor.svg?width=890)](https://opencollective.com/goproxy)\n[![Enterprise Supporters](https://opencollective.com/goproxy/tiers/enterprise.svg?width=890)](https://opencollective.com/goproxy)\n\n## Maintainers\n- [Elazar Leibovich](https://github.com/elazarl): Creator of the project, Software Engineer\n- [Erik Pellizzon](https://github.com/ErikPelli): Maintainer, Freelancer (open to collaborations!)\n\nIf you need to integrate GoProxy into your project, or you need some custom\nfeatures to maintain in your fork, you can contact [Erik](mailto:erikpelli@tutamail.com)\n(the current maintainer) by email, and you can discuss together how he\ncan help you as a paid independent consultant.\n\n## Contributions\nIf you have any trouble, suggestion, or if you find a bug, feel free to reach\nout by opening a GitHub `issue`.\nThis is an `open source` project managed by volunteers, and we're happy\nto discuss anything that can improve it.\n\nMake sure to explain everything, including the reason behind the issue\nand what you want to change, to make the problem easier to understand.\nYou can also directly open a `Pull Request`, if it's a small code change, but\nyou need to explain in the description everything.\nIf you open a pull request named `refactoring` with `5,000` lines changed,\nwe won't merge it... `:D`\n\nThe code for this project is released under the `BSD 3-Clause` license,\nmaking it useful for `commercial` uses as well.\n\n### Submit your case study\nSo, you have introduced \u0026 integrated GoProxy into one of your personal projects\nor a project inside the company you work for.\n\nWe're happy to learn about new `creative solutions` made with this library,\nso feel free to `contact` the maintainer listed above via e-mail, to explaining\nwhy you found this project useful for your needs.\n\nIf you have signed a `Non Disclosure Agreement` with the company, you\ncan propose them to write a `blog post` on their official website about\nthis topic, so this information will be public by their choice, and you can\n`share the link` of the blog post with us :)\n\nThe purpose of case studies is to share with the `community` why all the\n`contributors` to this project are `improving` the world with their help and\nwhat people are building using it.\n\n### Linter\nThe codebase uses an automatic lint check over your Pull Request code.\nBefore opening it, you should check if your changes respect it, by running\nthe linter in your local machine, so you won't have any surprise.\n\nTo install the linter:\n```sh\ngo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest\n```\n\nThis will create an executable in your `$GOPATH/bin` folder\n(`$GOPATH` is an environment variable, usually\nits value is equivalent to `~/go`, check its value in your machine if you\naren't sure about it).\nMake sure to include the bin folder in the path of your shell, to be able to\ndirectly use the `golangci-lint run` command.\n\n## A taste of GoProxy\n\nTo get a taste of `goproxy`, here you are a basic HTTP/HTTPS proxy\nthat just forward data to the destination:\n\n```go\npackage main\n\nimport (\n    \"log\"\n    \"net/http\"\n\n    \"github.com/elazarl/goproxy\"\n)\n\nfunc main() {\n    proxy := goproxy.NewProxyHttpServer()\n    proxy.Verbose = true\n    log.Fatal(http.ListenAndServe(\":8080\", proxy))\n}\n```\n\n### Request handler\nThis line will add `X-GoProxy: yxorPoG-X` header to all requests sent through the proxy,\nbefore sending them to the destination:\n\n```go\nproxy.OnRequest().DoFunc(\n    func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {\n        r.Header.Set(\"X-GoProxy\",\"yxorPoG-X\")\n        return r,nil\n    })\n```\n\nWhen the `OnRequest()` input is empty, the function specified in `DoFunc`\nwill process all incoming requests to the proxy. In this case, it will add\na header to the request and return it to the caller.\nThe proxy will send the modified request to the destination.\nYou can also use `Do` instead of `DoFunc`, if you implement the specified\ninterface in your type.\n\n\u003e ⚠️ Note we returned a nil value as the response.\n\u003e If the returned response is not nil, goproxy will discard the request\n\u003e and send the specified response to the client.\n\n### Conditional Request handler\nRefuse connections to www.reddit.com between 8 and 17 in the server\nlocal timezone:\n\n```go\nproxy.OnRequest(goproxy.DstHostIs(\"www.reddit.com\")).DoFunc(\n    func(req *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) {\n        if h,_,_ := time.Now().Clock(); h \u003e= 8 \u0026\u0026 h \u003c= 17 {\n\t\t\tresp := goproxy.NewResponse(req, goproxy.ContentTypeText, http.StatusForbidden, \"Don't waste your time!\")\n            return req, resp\n        }\n        return req, nil\n})\n```\n\n`DstHostIs` returns a `ReqCondition`, which is a function receiving a `*http.Request`\nand returning a boolean that checks if the request satisfies the condition (and that will be processed).\n`DstHostIs(\"www.reddit.com\")` will return a `ReqCondition` that returns true\nwhen the request is directed to \"www.reddit.com\".\nThe host equality check is `case-insensitive`, to reflect the behaviour of DNS\nresolvers, so even if the user types \"www.rEdDit.com\", the comparison will\nsatisfy the condition.\nWhen the hour is between 8:00am and 5:59pm, we directly return\na response in `DoFunc()`, so the remote destination will not receive the\nrequest and the client will receive the `\"Don't waste your time!\"` response.\n\n### Let's start\n```go\nimport \"github.com/elazarl/goproxy\"\n```\n\nThere are some proxy usage examples in the `examples` folder, which\ncover the most common cases. Take a look at them and good luck!\n\n## Request \u0026 Response manipulation\n\nThere are 3  different types of handlers to manipulate the behavior of the proxy, as follows:\n\n```go\n// handler called after receiving HTTP CONNECT from the client, and\n// before proxy establishes connection with the destination host\nhttpsHandlers   []HttpsHandler\n\n// handler called before proxy sends HTTP request to destination host\nreqHandlers     []ReqHandler \n\n// handler called after proxy receives HTTP Response from destination host,\n// and before proxy forwards the Response to the client\nrespHandlers    []RespHandler \n```\n\nDepending on what you want to manipulate, the ways to add handlers to each of the previous lists are:\n\n```go\n// Add handlers to httpsHandlers \nproxy.OnRequest(some ReqConditions).HandleConnect(YourHandlerFunc())\n\n// Add handlers to reqHandlers\nproxy.OnRequest(some ReqConditions).Do(YourReqHandlerFunc())\n\n// Add handlers to respHandlers\nproxy.OnResponse(some RespConditions).Do(YourRespHandlerFunc())\n```\n\nExample:\n\n```go\n// This rejects the HTTPS request to *.reddit.com during HTTP CONNECT phase.\n// Reddit URL check is case-insensitive because of (?i), so the block will work also if the user types something like rEdDit.com.\nproxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile(\"(?i)reddit.*:443$\"))).HandleConnect(goproxy.AlwaysReject)\n\n// Be careful about this example! It shows you a common error that you\n// need to avoid.\n// This will NOT reject the HTTPS request with URL ending with .gif because,\n// if the scheme is HTTPS, the proxy will receive only URL.Hostname\n// and URL.Port during the HTTP CONNECT phase.\nproxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).HandleConnect(goproxy.AlwaysReject)\n\n// To fix the previous example, here there is the correct way to manipulate\n// an HTTP request using URL.Path (target path) as a condition.\nproxy.OnRequest(goproxy.UrlMatches(regexp.MustCompile(`.*gif$`))).Do(YourReqHandlerFunc())\n```\n\n## Error handling\n### Generic error\nIf an error occurs while handling a request through the proxy, by default\nthe proxy returns HTTP error `500` (Internal Server Error) with the `error\nmessage` as the `body` content.\n\nIf you want to override this behaviour, you can define your own\n`RespHandler` that changes the error response.\nAmong the context parameters, `ctx.Error` contains the `error` occurred,\nif any, or the `nil` value, if no error happened.\n\nYou can handle it as you wish, including returning a custom JSON as the body.\nExample of an error handler:\n```\nproxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {\n\tvar dnsError *net.DNSError\n\tif errors.As(ctx.Error, \u0026dnsError) {\n\t\t// Do not leak our DNS server's address\n\t\tdnsError.Server = \"\u003cserver-redacted\u003e\"\n\t\treturn goproxy.NewResponse(ctx.Req, goproxy.ContentTypeText, http.StatusBadGateway, dnsError.Error())\n\t}\n\treturn resp\n})\n```\n\n### Connection error\nIf an error occurs while sending data to the target remote server (or to\nthe proxy client), the `proxy.ConnectionErrHandler` is called to handle the\nerror, if present, else a `default handler` will be used.\nThe error is passed as `function parameter` and not inside the proxy context,\nso you don't have to check the ctx.Error field in this handler.\n\nIn this handler you have access to the raw connection with the proxy\nclient (as an `io.Writer`), so you could send any HTTP data over it,\nif needed, containing the error data.\nThere is no guarantee that the connection hasn't already been closed, so\nthe `Write()` could return an error.\n\nThe `connection` will be `automatically closed` by the proxy library after the\nerror handler call, so you don't have to worry about it.\n\n## Project Status\nThis project has been created `10 years` ago, and has reached a stage of\n`maturity`. It can be safely used in `production`, and many projects\nalready do that.\n\nIf there will be any `breaking change` in the future, a `new version` of the\nGo module will be released (e.g. v2).\n\n## Trusted, as a direct dependency, by:\n\u003cp align=\"left\"\u003e\n\u003ca href=\"https://github.com/stripe/goproxy\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/856813?s=50\" alt=\"Stripe\" title=\"Stripe\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/dependabot/goproxy\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/27347476?s=50\" alt=\"Dependabot\" title=\"Dependabot\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/go-git/go-git\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/57653224?s=50\" alt=\"Go Git\" title=\"Go Git\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/google/oss-rebuild\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/1342004?s=50\" alt=\"Google\" title=\"Google\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/grafana/grafana-plugin-sdk-go\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/7195757?s=50\" alt=\"Grafana\" title=\"Grafana\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/superfly/tokenizer\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/22525303?s=50\" alt=\"Fly.io\" title=\"Fly.io\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/kubernetes/minikube\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/13629408?s=50\" alt=\"Kubernetes / Minikube\" title=\"Kubernetes / Minikube\" /\u003e \u003c/a\u003e\n\u003ca href=\"https://github.com/newrelic/newrelic-client-go\" target=\"_blank\" rel=\"noreferrer\"\u003e \u003cimg src=\"https://avatars.githubusercontent.com/u/31739?s=50\" alt=\"New Relic\" title=\"New Relic\" /\u003e \u003c/a\u003e\n\u003c/p\u003e\n","funding_links":["https://opencollective.com/goproxy"],"categories":["语言资源库","开源类库","Go","Networking","Open source library","网络","Recently Updated","\u003ca name=\"Go\"\u003e\u003c/a\u003eGo"],"sub_categories":["go","网络","Transliteration","The Internet","音译","[Jan 30, 2025](/content/2025/01/30/README.md)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felazarl%2Fgoproxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felazarl%2Fgoproxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felazarl%2Fgoproxy/lists"}