我对 go http 包进行了一些实验。
看下面的代码片段,一个非常简单的http服务器:
package main
import (
"fmt"
"github.com/codegangsta/negroni"
"github.com/gorilla/mux"
"net/http"
//"time"
)
type controller struct {
request *http.Request
response http.ResponseWriter
}
func (self *controller) send() {
fmt.Fprintf(self.response, "Request %p and Response %p \n", self.request, self.response)
}
func (self *controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
fmt.Println("Start controller")
self.request = r
self.response = rw
self.send()
}
func main() {
router := mux.NewRouter()
router.Handle("/", &controller{})
n := negroni.Classic()
n.UseHandler(router)
n.Run(":3000")
}
然后我向服务器发出 20 次请求:
package main
import (
"fmt"
"io"
"net/http"
"runtime"
"time"
)
func main() {
buffer := make([]byte, 100)
runtime.GOMAXPROCS(runtime.NumCPU())
for i := 0; i < 20; i++ {
go func(z int) {
//fmt.Println("Request goroutine 1 ", z)
resp, err := http.Get("http://127.0.0.1:3000")
if err != nil {
fmt.Println(err)
}
io.ReadFull(resp.Body, buffer)
fmt.Println(string(buffer))
}(i)
}
time.Sleep(time.Second * 5)
}
我收到了以下回复:
Request 0xc0820201a0 and Response 0xc082007100
Request 0xc082021380 and Response 0xc0820072c0
Request 0xc0820204e0 and Response 0xc082007740
Request 0xc082020dd0 and Response 0xc0820071c0
Request 0xc082020d00 and Response 0xc082007240
Request 0xc082021450 and Response 0xc082007400
Request 0xc082020f70 and Response 0xc082007500
Request 0xc082021110 and Response 0xc082007480
Request 0xc0820212b0 and Response 0xc082007540
Request 0xc082020b60 and Response 0xc0820075c0
Request 0xc082020750 and Response 0xc082007640
Request 0xc082020270 and Response 0xc0820076c0
Request 0xc082020c30 and Response 0xc082007840
Request 0xc082020820 and Response 0xc0820078c0
Request 0xc082020ea0 and Response 0xc082007940
Request 0xc0820211e0 and Response 0xc0820079c0
Request 0xc082021520 and Response 0xc082007a40
Request 0xc0820209c0 and Response 0xc082007ac0
Request 0xc082021040 and Response 0xc082007380
Request 0xc082020a90 and Response 0xc0820077c0
如您所见,一切正常。每个请求和响应都有不同的存储地址。
所以如果我将 http 服务器更改为:
package main
import (
"fmt"
"github.com/codegangsta/negroni"
"github.com/gorilla/mux"
"net/http"
"time"
)
type controller struct {
request *http.Request
response http.ResponseWriter
counter int
}
func (self *controller) get() {
self.counter++
if self.counter == 7 {
time.Sleep(time.Second * 4)
}
fmt.Printf("Request %p and Response %p \n", self.request, self.response)
}
func (self *controller) send() {
fmt.Fprintf(self.response, "Request %p and Response %p \n", self.request, self.response)
}
func (self *controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
fmt.Println("Start controller")
self.request = r
self.response = rw
self.get()
self.send()
}
func main() {
router := mux.NewRouter()
router.Handle("/", &controller{})
n := negroni.Classic()
n.UseHandler(router)
n.Run(":3000")
}
正如您在这里看到的,我添加了方法 get,当计数器达到数字 7 时,它将休眠 4 秒。
func (self *controller) get() {
self.counter++
if self.counter == 7 {
time.Sleep(time.Second * 4)
}
fmt.Printf("Request %p and Response %p \n", self.request, self.response)
}
作为输出我有
Request 0xc082021040 and Response 0xc082007100
Request 0xc0820209c0 and Response 0xc082007240
Request 0xc0820211e0 and Response 0xc082007380
Request 0xc082020270 and Response 0xc082007500
Request 0xc082020d00 and Response 0xc082007640
Request 0xc082020f70 and Response 0xc082007740
Request 0xc082020680 and Response 0xc082007840
Request 0xc082020820 and Response 0xc082007940
Request 0xc082020b60 and Response 0xc082007a40
Request 0xc082021380 and Response 0xc0820071c0
Request 0xc082021110 and Response 0xc0820072c0
Request 0xc0820208f0 and Response 0xc082007400
Request 0xc082020a90 and Response 0xc082007540
Request 0xc082020340 and Response 0xc0820076c0
Request 0xc082020750 and Response 0xc0820075c0
Request 0xc082020dd0 and Response 0xc0820077c0
Request 0xc0820212b0 and Response 0xc0820078c0
Request 0xc0820201a0 and Response 0xc0820079c0
Request 0xc082020ea0 and Response 0xc082007ac0
Request 0xc082020ea0 and Response 0xc082007ac0
可以看到最后两行的地址是一样的,也就是说request 7会覆盖request和response的地址,因为response是delay的。
我的问题是,当一个请求必须处理密集的计算时,例如调整图像大小,并且在调整大小期间另一个请求进来,来自图像调整大小过程的请求和响应将像上面那样被覆盖。然后响应将转到最后请求的客户端。在我看来,这是错误的,对吧?
我知道为每个请求创建一个新的 goroutine。
最佳答案
您正在引入数据竞赛:
router.Handle("/", &controller{})
如您所见,controller 类型只有一个实例。
self.request = r
self.response = rw
在这里你正在修改你的结构。但是 ServeHTTP() 方法会被多个 goroutines 调用。
一个选项是像这样创建一个处理程序
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
c := &controller{request: r, response: w)
c.send()
...
})
如果您使用 -race 标志运行您的代码,它会警告您这一点。另见 http://blog.golang.org/race-detector
另一件事:不要给你的接收者命名self。这不是惯用语。它使您的代码不可读。什么是 self?给它一个合适的名字。
关于go - Request 和 ResponseWriter 将被覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27153811/
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
request.cookies和RubyonRails中的cookies对象有区别吗?我目前正在尝试将带有cookie的请求从我的node.js服务器发送到我的ROR4应用程序。似乎在ROR应用程序中,request.cookies包含我发送的cookie,但是cookies对象(现有逻辑所基于的对象)没有它。我已经搜索了文档,但找不到任何相关内容。我错过了什么吗?感谢您的帮助。 最佳答案 理想情况下,request.cookies和cookies应该相同。但是,在POST(创建操作)请求中,rails会验证XSRFtoken。如果
我的Ruby-on-Rails项目中有以下文件结构,用于规范:/spec/msd/serviceservice_spec.rb/support/my_modulerequests_stubs.rb我的request_stubs.rb有:moduleMyModule::RequestsStubsmodule_functiondeflist_clientsurl="dummysite.com/clients"stub_request(:get,url).to_return(status:200,body:"clientsbody")endend在我的service_spec.rb我有:re
我正在尝试根据RyanBatesscreencastonsubdomains在Rails3中设置子域.但是它对我不起作用。我有以下设置:#routes.rbconstraints(Subdomain)doget'devices'=>'devices#all'end#lib/subdomain.rbclassSubdomaindefself.matches?(request)#binding.pryrequest.subdomain.present?&&request.subdomain=="admin"endend加载urladmin.localhost:3000/devices应该将
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol
是否有chrome开关来抑制“外部协议(protocol)请求”?我正在使用selenium-ruby-watirwebdriver自动化应用程序。我在网上搜索了绕过此窗口和对话的解决方案:http://productforums.google.com/forum/#!topic/chrome/K22hXwRy6zQ概述了我们如何手动执行此操作。但是对于Selenium-Chrome-Ruby,我需要通过可能设置一个chrome开关(chorme开关列表:=http://src.chromium.org/svn/trunk/src/chrome/common/chrome_swit
我在一台Windows764位机器上使用Sass和Ruby(最新版本),我正在我的家庭服务器上处理一个共享文件夹。(但是,我不得不承认问题本身也出现在服务器上,因为我试图安装Ruby并直接-watch服务器上的文件)。问题如下:如果我第一次保存,检测到变化,我的style.css被直接覆盖。之后,我总是需要保存多达7次才能覆盖style.css。每次都会检测到更改,但不会编译任何内容。这是一个屏幕:>>>Sassiswatchingforchanges.PressCtrl-Ctostop.overwritestyle.css>>>Changedetectedto:E:/Websites
我想在请求期间动态更改ActiveRecord模型类的表名。例如,有许多具有相似结构(列)的表:mydb:sample_data_12222sample_data_12223sample_data_12224sample_data_12225...所以,我想做的是..._1。定义基本模型类,如:classSampleData_2。在请求期间更改目标表,例如:defaction_methodSampleData.set_table_name"sample_data_#{params[:id]}"@rows=SampleData.all如果在非线程环境(如Passenger/mod_rai
比如说,我有以下2个类:classAdefa_methodendendclassB是否可以从B类(的一个实例)中检测到a_method方法仅在父类(superclass)中定义,因此不会在B中被覆盖?更新:解决方案虽然我已将Chuck的回答标记为“已接受”,但后来PaoloPerrota让我意识到该解决方案显然可以更简单,并且它可能也适用于早期版本的Ruby。检测“a_method”是否在B中被覆盖:B.instance_methods(false).include?("a_method")对于类方法,我们同样使用singleton_methods:B.singleton_method
我正在尝试使用RubygemRestClient为我的一个FusionTables更新样式。这是我的代码:require'rest_client'tableId=''styleId=''key=''table_url="https://www.googleapis.com/fusiontables/v1/tables/#{tableId}/styles/#{styleId}?key=#{key}"update='{"polygonOptions":{"strokeColor":"#ffffff"}}'token='STRINGCONTAININGAUTHORIZATIONTOKEN'R