{"id":29,"date":"2019-02-04T15:20:54","date_gmt":"2019-02-04T14:20:54","guid":{"rendered":"https:\/\/blog.simon-frey.eu\/?p=29"},"modified":"2024-03-22T10:47:08","modified_gmt":"2024-03-22T09:47:08","slug":"go-as-in-golang-standard-net-http-config-will-break-your-production","status":"publish","type":"post","link":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/","title":{"rendered":"Standard net\/http config will break your production environment"},"content":{"rendered":"\n<p>or a less click baity title: <strong>An introduction to net\/http timeouts<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>First of all, as you may already recognized from the titles, this blogpost is standing on the shoulder of giants. The following two blog posts inspired me to revise the net\/http timeouts, as the linked blog post are at some parts outdated:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/blog.cloudflare.com\/the-complete-guide-to-golang-net-http-timeouts\/\">The complete guide to golang net\/http timeouts<\/a><\/li><li><a href=\"https:\/\/medium.com\/@nate510\/don-t-use-go-s-default-http-client-4804cb19f779\">Don&#8217;t use Go&#8217;s default http client<\/a><\/li><\/ul>\n\n\n\n<p>Give them a visit after  you read this post and see how things have changed in such a short time \ud83d\ude09<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"why-you-should-not-use-the-standard-net-http-config\">Why you should not use the standard net\/http config?<\/h2>\n\n\n\n<p>The go core team decided to not set any timeouts at all on the standard net\/http client or server config and that is a real sane decision. Why?<\/p>\n\n\n\n<p>To not break things! Timeouts are a highly individual setting and in more of the cases a to short timeout will break your application with a unexplainable error, than a too long one (or in GOs case none) would.<\/p>\n\n\n\n<p>Imaging following different use cases of the go net\/http client:<\/p>\n\n\n\n<p>1) Downloading a big file (10GB) from a webserver. With an average (german) internet connection this would take round about five minutes.<\/p>\n\n\n\n<p>=&gt; The timeout for the connection should be longer than five minutes, because anything less would break your application by canceling the download in the middle (or third, or whatever percentage) of the file.<\/p>\n\n\n\n<p>2) Accessing a REST API with a lot of concurrent connections. This normally should take at most a few seconds per connection<\/p>\n\n\n\n<p>=&gt; The timeout should be not more than 10 seconds, as anything that takes longer would mean, that you are keeping that connection open for to long and starving your application as it only can have X (depending on system, configuration and coding) open connections. So if that REST API you access is broken in any way that it keeps the connections open without sending you the data you need, you want to prevent it from doing so.<\/p>\n\n\n\n<p>So, for what scenario should the standard lib be optimized? Trust me, you do not want to decide that for millions of developers around the globe.<\/p>\n\n\n\n<p>That is why we have to set the timeouts, so that they fit our use case!<\/p>\n\n\n\n<p><strong>So never use the standard go http client\/server! It will break your production system!<\/strong> <em>(Happened to me, as I forgot my own rule ones)<\/em><\/p>\n\n\n<div class=\"lazyblock-ad-Zvqnoh wp-block-lazyblock-ad\"><div style=\"display:none;font-family:sans-serif; border:2px solid #00000020;padding: 0.5em;margin-top:1em;margin-bottom:1em;\">\n  <div style=\"display:flex;justify-content:center;align-items:center;gap:10px;\">\n  <div style=\"line-height: 1.3em;text-align:left;\"><h3>Highly skilled DevOps\/SRE Freelancer<\/h3>\n  <p>I am Simon, the author of this blog. And I have great news: <b style=\"font-weight:bold;\">You can work with me<\/b><\/p>\n  <p>As DevOps and Infrastructure freelancer, I will help you choose the right Infrastructure technology for your company, fix your cloud problems and support your team in building scalable products.<\/p>\n  <p>I work with Golang, Docker, Kubernetes, Google Cloud, AWS and Terraform.<\/p>\n  <p>Checkout my <a href=\"https:\/\/simon-frey.com\/cv\" target=\"_blank\">CV<\/a> to learn more or directly contact me via the button below.<\/p>\n  <\/div>  \n  <img decoding=\"async\" data-src=\"https:\/\/simon-frey.com\/cv\/img\/simon-frey.jpg\" alt=\"Simon Frey Header image\" style=\"height:10em;\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" class=\"lazyload\">\n\n  <\/div>\n  \n  <a href=\"mailto:contact@simon-frey.com\" style=\"display:block;text-align:center;color:black;text-decoration:none;border:solid 2px black;padding:10px;border-radius:5px;margin-top:1em;\">Let&#8217;s work together!<\/a>\n<\/div><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"what-type-of-timeouts-occur-in-a-http-connection\">What type of timeouts occur in a HTTP connection?<\/h2>\n\n\n\n<p>I assume you have a basic understanding of the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Transmission_Control_Protocol\">TCP<\/a> and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol\">HTTP<\/a> protocols. (If not, Wikipedia is a good starting point for that)<\/p>\n\n\n\n<p>There are mainly three different categories of timeouts that can occur:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>During connection setup<\/li><li>During receiving\/sending the header information<\/li><li>During receiving\/sending the body<\/li><\/ul>\n\n\n\n<p>As you already might expect from our two examples in the introduction, the timeout that we have to care about the most is the one regarding the body. The other ones are most of the time shorter and similar in every setup. (E.g. there is only a certain amount of headers that will be send) We still have to think and care about timeouts in the header as there are certain DOS attacks that play with malformed headers, or never closing a header (<a href=\"https:\/\/www.slashroot.in\/slowloris-http-dosdenial-serviceattack-and-prevention\">SLOWLORIS DOS attack<\/a>) but we will come to this in a later point of the post.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"you-should-at-least-do-this-the-easy-path\">You should at least do this: The easy path<\/h2>\n\n\n\n<p>net\/http gives you the possibility to set a timeout for the complete transfer of data (setup, headers, body). It is not as fine  grained as with the later bespoken solutions, but it will help you to prevent the most obvious problems:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Connection starving<\/li><li>Malformed header attacks<\/li><\/ul>\n\n\n\n<p><strong>So you should at least use this timeouts on every go net\/http client\/server you use!<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"client\">Client<\/h3>\n\n\n\n<p>The following example client, gives you a complete timeout of 5 seconds.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>c := &amp;http.Client{\n\tTimeout: 5 * time.Second,\n}\nc.Get(\"https:\/\/blog.simon-frey.eu\/\")\n<\/code><\/pre>\n\n\n\n<p>If the connection is still open, it will be canceled with <code>net\/http: request canceled (Client.Timeout exceeded while reading ...)<\/code><\/p>\n\n\n\n<p>So this timeout would work for small files, but not for download of a large file. We will see how we can have a variable timeout for the body later in the post.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"server\">Server<\/h3>\n\n\n\n<p>For the server we have to set two timeouts in the easy setup. Read and write. So the <code>ReadTimeout<\/code> defines how long you allow a connection to be open during a client sends data. And with <code>WriteTimeout<\/code> it is in the other direction. (Yeah it could also be, that you send data somewhere and the packages never get accepted <code>TCP-ACK<\/code> and your server would starve again)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>s := &amp;http.Server{\n\tReadTimeout: 1 * time.Second,\n\tWriteTimeout: 10 * time.Second,\n\tAddr:\":8080\",\n}\ns.ListenAndServe()\n<\/code><\/pre>\n\n\n\n<p>So this server would listen on port <code>8080<\/code> and have your desired timeouts.<\/p>\n\n\n\n<p><strong>For a lot of use cases, this easy path may be enough. But please read on and see what other things are possible \ud83d\ude00<\/strong><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"client-in-depth-configuration-of-timeouts\">[Client] In-depth configuration of  timeouts<\/h2>\n\n\n\n<p>One thing to note before we get started here is the following differentiation:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Easy path timeout <em>(above)<\/em> is defined for a complete request including redirects<\/li><li>The following configurations are per connection.(As they are defined via <code>http.Transport<\/code>, which has no information about redirects itself) So if there happen a lot of redirects, the timeouts add up per connection. You can use both, to prevent endless redirects<\/li><\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"connection-setup\">Connection setup<\/h3>\n\n\n\n<p>In the following setup are two parameters, we set with a timeout. They differ in their connection type:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>DialContext<\/code>: Defines the setup timeout for an unencrypted HTTP connection<\/li><li><code>TLSHandshakeTimeout<\/code>: Cares about the setup timeout for upgrading the unencrypted connection to an encryped one HTTPS<\/li><\/ul>\n\n\n\n<p>In a 2019 setup, you should always try to talk to encrypted HTTPS endpoints, so there are very rare cases where it makes sense to only set one of the two parameters.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> c := &amp;http.Client{\n    Transport: &amp;http.Transport{\n\t\tDialContext:(&amp;net.Dialer{\n\t\t\tTimeout:   3 * time.Second,\n\t\t}).DialContext,\n\t\tTLSHandshakeTimeout:   10 * time.Second,\n    }\n}\nc.Get(\"https:\/\/blog.simon-frey.eu\/\")\n<\/code><\/pre>\n\n\n\n<p>With setting these parameters you define how long the setup of a connection should last at longest. This helps you with &#8216;detecting&#8217; (for actually detection you have to do more than this few lines) of hosts that are down in a faster manner. So you are not waiting in your project for a host, that is\/was down in the first place.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"response-headers\">Response headers<\/h3>\n\n\n\n<p>Now as we have an established (hopefully HTTPS) connection, we have to receive the meta information about the content we get. This meta information is stored in the headers. We can set timeouts, how long we want the server to be able to answer us.<\/p>\n\n\n\n<p>Here again are two different timeouts to be defined:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code>ExpectContinueTimeout<\/code>:  This configures how long you want to wait after you send your payload for the beginning of an answer (in form of the beginning of the header)<\/li><li><code>ResponseHeaderTimeout<\/code>:  And with this parameter you set how long the complete transfer of the header is allowed to last<\/li><\/ul>\n\n\n\n<p>So you want to have the complete header information <code>ExpectContinueTimeout<\/code> + <code>ResponseHeaderTimeout<\/code> after your did send you complete request<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>c := &amp;http.Client{\n\tTransport: &amp;http.Transport{\n\t\tExpectContinueTimeout: 4 * time.Second,\n\t\tResponseHeaderTimeout: 10 * time.Second,\n    },\n}\nc.Get(\"https:\/\/blog.simon-frey.eu\/\")\n<\/code><\/pre>\n\n\n\n<p>With setting this parameters, we can define how long we accept the server to take for an answer and therefore also for internal operations.<\/p>\n\n\n\n<p>Imagine following scenario: <em>Your access an API, that will resize an image you send to it. So you upload the image and normally it takes ~1 second to resize the image and than start sending it back to your service. But maybe the API crashes of whatever reasons and takes 60 seconds to resize the image. As you now defined the timeouts, you can abort after a couple of seconds and tell your own customers that API xyz is down and that you are in contact with the supplier&#8230;better than having your fancy image editor loading for ages and not showing any status information, and that all because of a bug that is not even your fault!<\/em><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"body\">Body<\/h3>\n\n\n\n<p>Per definition, the timeout for the body is the hardest, as this is the part of the response that will vary the most in size and thereby time it needs for transfer.<\/p>\n\n\n\n<p>We will cover two approaches that help you to define a timeout on the body:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Static timeout, that kills the transfer after a certain amount of time<\/li><li>Variable timeout, that kills the timeout after there was no data transfered for a certain amount of time<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"static-timeout\">Static timeout<\/h4>\n\n\n\n<p><strong>We are dropping all errors in the example code. You should not do that!<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>c := &amp;http.Client{}\nresp, _ := c.GET(\"https:\/\/blog.simon-frey.eu\")\ndefer resp.Body.Close()\n\ntime.AfterFunc(5*time.Second, func() {\n\tresp.Body.Close()\n})\nbodyBytes,_ := ioutil.ReadAll(resp.Body)\t\n<\/code><\/pre>\n\n\n\n<p>In the code example we set a timer, that executes <code>resp.Body.Close()<\/code> after it finished. With this command we close the body and the <code>ioutil.ReadAll<\/code> will throw a <code>read on closed response body<\/code> error.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"variable-timeout\">Variable timeout<\/h4>\n\n\n\n<p><strong>We are dropping most of the errors in the example code. You should not do that!<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>c := &amp;http.Client{}\nresp, _ := c.GET(https:\/\/blog.simon-frey.eu\")\ndefer resp.Body.Close()\n\ntimer := time.AfterFunc(5*time.Second, func() {\n\tresp.Body.Close()\n})\t\n                 \nbodyBytes := make(&#91;]byte, 0)\nfor {\n\t\/\/We reset the timer, for the variable time\n\ttimer.Reset(1 * time.Second)\n\n\t_, err = io.CopyN(bytes.NewBuffer(bodyBytes), resp.Body, 256)\n\tif err == io.EOF {\n\t\t\/\/ This is not an error in the common sense\n        \/\/ io.EOF tells us, that we did read the complete body\n\t\t\tbreak\n\t} else if err != nil {\n\t\t\/\/You should do error handling here\n        break\n\t}\n}\n<\/code><\/pre>\n\n\n\n<p>The difference here is, that we have a endless loop, that iterates over the body and copies data out of it. There are two options how this loop will be left:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>We get the <code>io.EOF<\/code> file error from <code>io.CopyN<\/code>, this means we read the complete body and no timeout neds to be triggered<\/li><li>We get another error, if that error is the <code>read on closed response body<\/code> error the timeout triggered.<\/li><\/ul>\n\n\n\n<p>This solutions works, because <code>io.CopyN<\/code> is blocking. So if there is not enough (in our case 256 bytes) to read from the body it will wait. If the timeout triggers during that time, we stop the execution.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"my-default-config\">My &#8216;default&#8217; config<\/h3>\n\n\n\n<p>Again: <strong>This is my very own opinion on the timeouts and you should adapt them to the requirements of your project!<\/strong> I do not use this exact same setup in every project!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>c := &amp;http.Client{\n\tTransport: &amp;http.Transport{\n\t\tDialContext:(&amp;net.Dialer{\n\t\t\tTimeout:   10 * time.Second,\n\t\t\tKeepAlive: 10 * time.Second,\n\t\t}).DialContext,\n\t\tTLSHandshakeTimeout:   10 * time.Second,\n           \n\t\tExpectContinueTimeout: 4 * time.Second,\n\t\tResponseHeaderTimeout: 3 * time.Second,\n\t\t\n        \/\/ Prevent endless redirects\n        Timeout: 10 * time.Minute,\n\t},\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"server-in-depth-configuration-of-timeouts\">[Server] In-depth configuration of  timeouts<\/h2>\n\n\n\n<p>As there are no certain dial up timeouts for <code>http.Server<\/code> we will directly start into the timeouts for the headers.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"headers\">Headers<\/h3>\n\n\n\n<p>For the request headers we have a certain timeout: <code>ReadeHeaderTimeout<\/code>, which represents the time until the full request header (send by a client) should be read. So if a client takes longer to send the headers the connection will time out. This timeout is especially important against attacks like <a href=\"https:\/\/www.slashroot.in\/slowloris-http-dosdenial-serviceattack-and-prevention\">SLOWLORIS<\/a> as here the header never gets closed and the connection thereby will be kept open all the time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>s := &amp;http.Server{\n\tReadHeaderTimeout:20 *time.Second,\n}\ns.ListenAndServe()\n<\/code><\/pre>\n\n\n\n<p>As you may already have recognized, there is only a <strong>Read<\/strong>HeaderTimeout, because for the sending of data to the client go does not have a certain distinction between the headers and the body for the timeout<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"body-1\">Body<\/h3>\n\n\n\n<p>Here we have to differentiate between request (that is send from the client to the server) and the response body.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"response-body\">Response body<\/h4>\n\n\n\n<p>For the response body there is only one static solution for a timeout:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>s := &amp;http.Server{\n\tWriteTimeout:20 *time.Second,\n}\ns.ListenAndServe()\n<\/code><\/pre>\n\n\n\n<p>As long as the connection is open, we can not differentiate if the data was send correctly or if the client is doing bogus here. But as we know our payload data, it is quite straight forward to set the timeout here on our past information we have about our server. So if you are a file server this timeout should be longer than for a API server. You can set no timeout for testing purpose and track how long a &#8216;normal&#8217; request takes. Add a few percent of variance there and then you should be good to go!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"request-body\">Request body<\/h4>\n\n\n\n<p>**Attention: If you did set the WriteTimeout it will have an effect on the request timeout as well. This is because of the defintion if the <code>WriteTimeout<\/code>. It starts when the headers of the request where read. ** <em>So if reading from the request body takes 5 seconds and your write timeout is 4 seconds it will also kill the reading of the request body!<\/em><\/p>\n\n\n\n<p>For the request body there are again two possible solutions:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Static timeouts that we can define via the <code>http.Client<\/code> config<\/li><li>Variable timeouts for that we have to build our own code workaround (as there is currently no support for that)<\/li><\/ul>\n\n\n\n<h5 class=\"wp-block-heading\" id=\"static\">Static<\/h5>\n\n\n\n<p>For a static timeout we can use the <code>ReadTimeout<\/code> parameter we already used in the easy path:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>s := &amp;http.Server{\n\tReadTimeout:20 * time.Second,\n}\ns.ListenAndServe()\n<\/code><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\" id=\"variable\">Variable<\/h5>\n\n\n\n<p>For the variable timeout we need to work on the level of the handlers. <strong>Do not set a <code>ReadTimeout<\/code>, because the static timeout will interfere with the variable one. Also you must not set <code>WriteTimeout<\/code> as it is counted from the end of the request header and thereby also will interfere with the variable header<\/strong><\/p>\n\n\n\n<p>We have to define our own handler for the server, in our example we call it <code>timeoutHandler<\/code>. This handler does nothing than reading from the body with our loop and timeout if there is no data send anymore.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>type timeoutHandler struct{}\nfunc (h timeoutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){\n\tdefer r.Body.Close()\n\n\ttimer := time.AfterFunc(5*time.Second, func() {\n\t\tr.Body.Close()\n\t})\n\n\tbodyBytes := make(&#91;]byte, 0)\n\tfor {\n\t\t\/\/We reset the timer, for the variable time\n\t\ttimer.Reset(1 * time.Second)\n        \n\t\t_, err := io.CopyN(bytes.NewBuffer(bodyBytes), r.Body, 256)\n\t\tif err == io.EOF {\n\t\t\t\/\/ This is not an error in the common sense\n\t\t\t\/\/ io.EOF tells us, that we did read the complete body\n\t\t\tbreak\n\t\t} else if err != nil {\n\t\t\t\/\/You should do error handling here\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc main() {\n\th := timeoutHandler{}\n\ts := &amp;http.Server{\n\t\tReadHeaderTimeout:20 *time.Second,\n\t\tHandler:h,\n\t\tAddr:\":8080\",\n\t}\n\ts.ListenAndServe()\n}\n<\/code><\/pre>\n\n\n\n<p>It is a similar approach to the one we did choose in the client. You have define this timeout loop in every handler you have separately. So you maybe should consider building a function for that, so that you don&#8217;t have to rewrite the coder over and over again.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"my-default-config-1\">My &#8216;default&#8217; config<\/h3>\n\n\n\n<p>Again: <strong>This is my very own opinion on the timeouts and you should adapt them to the requirements of your project!<\/strong> I do not use this exact same setup in every project!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>s := &amp;http.Server{\n\tReadHeaderTimeout:20 *time.Second,\n\tReadTimeout: 1 * time.Minute,\n\n    WriteTimeout: 2 * time.Minute,\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"conclusion\">Conclusion<\/h2>\n\n\n\n<p>I hope you liked this blog post and it helped you to understand the different timeouts in go a little bit better. If you have any feedback, questions or just want to say &#8216;Servus&#8217; (bavarian german for hello) do not hesitate to contact me!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p><strong>Sources<\/strong><\/p>\n\n\n\n<p><a href=\"https:\/\/golang.org\/pkg\/net\/http\/\">https:\/\/golang.org\/pkg\/net\/http\/<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/medium.com\/@nate510\/don-t-use-go-s-default-http-client-4804cb19f779\">https:\/\/medium.com\/@nate510\/don-t-use-go-s-default-http-client-4804cb19f779<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/blog.cloudflare.com\/exposing-go-on-the-internet\/\">https:\/\/blog.cloudflare.com\/exposing-go-on-the-internet\/<\/a><\/p>\n\n\n\n<p>Gopher Image (CC BY-SA 3.0): <a href=\"https:\/\/commons.wikimedia.org\/wiki\/File:Gophercolor.jpg\">Wikimedia<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>published with <a href=\"https:\/\/write.as\/\">write.as<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Updated information about how to use the net\/http package in production<\/p>\n","protected":false},"author":1,"featured_media":30,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[3],"tags":[28,5,6,16,17,18],"class_list":["post-29","post","type-post","status-publish","format-standard","hentry","category-golang","tag-german","tag-go","tag-golang","tag-http","tag-webdevelopment","tag-webserver"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Standard net\/http config will break your production environment - Blog by Simon Frey<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Simon Frey\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Standard net\/http config will break your production environment - Blog by Simon Frey","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/","twitter_misc":{"Written by":"Simon Frey","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#article","isPartOf":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/"},"author":{"name":"Simon Frey","@id":"https:\/\/simon-frey.com\/blog\/#\/schema\/person\/34753982b648415636ee7a079f3e19a3"},"headline":"Standard net\/http config will break your production environment","datePublished":"2019-02-04T14:20:54+00:00","dateModified":"2024-03-22T09:47:08+00:00","mainEntityOfPage":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/"},"wordCount":2162,"publisher":{"@id":"https:\/\/simon-frey.com\/blog\/#\/schema\/person\/34753982b648415636ee7a079f3e19a3"},"image":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#primaryimage"},"thumbnailUrl":"https:\/\/simon-frey.com\/blog\/wp-content\/uploads\/2019\/09\/Gophercolor.jpg","keywords":["german","go","golang","http","webdevelopment","webserver"],"articleSection":["Golang"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/","url":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/","name":"Standard net\/http config will break your production environment - Blog by Simon Frey","isPartOf":{"@id":"https:\/\/simon-frey.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#primaryimage"},"image":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#primaryimage"},"thumbnailUrl":"https:\/\/simon-frey.com\/blog\/wp-content\/uploads\/2019\/09\/Gophercolor.jpg","datePublished":"2019-02-04T14:20:54+00:00","dateModified":"2024-03-22T09:47:08+00:00","breadcrumb":{"@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#primaryimage","url":"https:\/\/simon-frey.com\/blog\/wp-content\/uploads\/2019\/09\/Gophercolor.jpg","contentUrl":"https:\/\/simon-frey.com\/blog\/wp-content\/uploads\/2019\/09\/Gophercolor.jpg","width":800,"height":504,"caption":"Golang gopher with pilot cap"},{"@type":"BreadcrumbList","@id":"https:\/\/simon-frey.com\/blog\/go-as-in-golang-standard-net-http-config-will-break-your-production\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/simon-frey.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Standard net\/http config will break your production environment"}]},{"@type":"WebSite","@id":"https:\/\/simon-frey.com\/blog\/#website","url":"https:\/\/simon-frey.com\/blog\/","name":"Blog by Simon Frey","description":"","publisher":{"@id":"https:\/\/simon-frey.com\/blog\/#\/schema\/person\/34753982b648415636ee7a079f3e19a3"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/simon-frey.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/simon-frey.com\/blog\/#\/schema\/person\/34753982b648415636ee7a079f3e19a3","name":"Simon Frey","logo":{"@id":"https:\/\/simon-frey.com\/blog\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/simon-frey.com","https:\/\/www.linkedin.com\/in\/simonfrey\/","https:\/\/x.com\/eu_frey"]}]}},"_links":{"self":[{"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/posts\/29","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/comments?post=29"}],"version-history":[{"count":5,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/posts\/29\/revisions"}],"predecessor-version":[{"id":1138,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/posts\/29\/revisions\/1138"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/media\/30"}],"wp:attachment":[{"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/media?parent=29"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/categories?post=29"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/simon-frey.com\/blog\/wp-json\/wp\/v2\/tags?post=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}