我正在编写一个小型网络服务器。我想阅读 HTTP 请求
。它在没有 body 参与时起作用。但是当发送正文时,我无法以令人满意的方式阅读正文的内容。
我通过TCPSocket
读取来自客户端的数据。 TCPSocket::gets
方法读取直到接收到正文数据。没有分隔符或 EOF
发送到 HTTP 请求正文结尾的信号。 HTTP/1.1 Specification - Section 4.4列出五种情况来获取消息长度。第 1 点有效。第 2) 和 4) 点与我的申请无关。第 5 点)不是一个选项,因为我需要发送回复。
我可以读取 Content-Length
字段的值。但是当我试图通过 read(contentlength)
或 rcv(contentlength)
“说服”TCPSocket 读取 HTTP 请求的最后一部分时,我没有成功。逐行阅读,直到分隔 Header 和 Body 的 \r\n
起作用,但在那之后我被卡住了 - 至少以我想要的方式。
所以我的问题是:
是否有可能像我在代码中预期的那样做?
有没有更好的方法来实现我正确读取 HTTP 请求
的目标(我真的希望如此)?
这是可运行的代码。我想工作的部分在评论中。
#!/usr/bin/ruby
require 'socket'
server = TCPServer.new 2000
loop do
Thread.start(server.accept) do |client|
hascontent = false
contentlength = 0
content = ""
request = ""
#This seems to work, but I'm not really happy with it, too much is happening in
#the loop
while(buf = client.readpartial(4096))
request = request + buf
split = request.split("\r\n")
puts request
puts request.dump
puts split.length
puts split.inspect
if(request.index("\r\n\r\n")>0)
break
end
end
#This part is commented out because it doesn't work
=begin
while(line = client.gets)
puts ":" + line
request = request + line
if(line.start_with?("Content-Length"))
hascontent = true
split = line.split(' ')
contentlength = split[1]
end
if(line == "\r\n" and !hascontent)
break
end
if(line == "\r\n" and hascontent)
puts "Trying to get content :P"
puts contentlength
puts content.length
puts client.inspect
#tried read, with and without parameter, rcv, also with and
#without param and their nonblocking couterparts
#where does my thought process go in the wrong direction
while(readin = client.readpartial(contentlength))
puts readin
content = content + readin
end
break
end
end
=end
puts request
client.close
end
最佳答案
所以...过去 2 小时我也遇到了这个问题,所以我深入研究了 Socket API。结果是 Socket
扩展了 BasicSocket
,它有一个方法 recvmsg
。当我尝试调用它时,我得到以下信息:
["GET / HTTP/1.1\r\nHost: localhost:12357\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n\r\n", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 0]
即我的完整 HTTP 请求、发件人的地址信息和任何其他 ruby 标记。
您可以使用 recvmsg 读取整个 HTTP 请求:
raw_request = client.recvmsg()
request = /(?<METHOD>\w+) \/(?<RESOURCE>[^ ]*) HTTP\/1.\d\r\n(?<HEADERS>(.+\r\n)*)(?:\r\n)?(?<BODY>(.|\s)*)/i.match(raw_request)
p request["BODY"]
如果没有 recvmsg
,我不知道该怎么做,但我很高兴该功能存在。
关于ruby - 无法使用 Ruby 1.9.3 正确读取 HTTP 请求 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16759978/