我正在编写一段Python代码来处理来自HTML服务器的POST请求方法。下面的代码块是在回答我之前提出的一个问题时提供给我的。我已经逐行检查了它,以确保我理解了这里的逻辑。但是我在这一行遇到了一个障碍。
第一个月
所以我将概述我认为逻辑是做什么的,然后提供实际的代码,我希望有人能在适当的地方纠正我,以确保我正确理解逻辑。此外,解释为什么上面的代码行存在,我不明白为什么在这种情况下需要split方法。
post_data不能简单地按原样打印出来吗?或者这会因为某种原因导致问题吗?
我在这里提供的顶部部分是上下文,因为它是程序的其余部分。
# Python 3 server example
from http.server import BaseHTTPRequestHandler, HTTPServer
import time #Why is time imported if it's not used? Hypothesis: the send response method on line 10 states among other things to send the current date. Thus time is needed to determine current date?
hostName = "localhost"
serverPort = 8080
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(bytes("<html><head><title>https://pythonbasics.org</title></head>", "utf-8"))
self.wfile.write(bytes("<p>Request: %s</p>" % self.path, "utf-8"))
self.wfile.write(bytes("<body>", "utf-8"))
self.wfile.write(bytes("<p>Hello world! This is a webpage!</p>", "utf-8"))
self.wfile.write(bytes("<p> And hello to you! Please enter your name below!</p>", "utf-8"))
self.wfile.write(bytes("""<form action="/" method="post">
<label for="name">Please enter your name:</label><br>
<input type="text" id="name" name="name"><br>
<input type = "submit" value = "Click me!">
</form>
""", "utf-8" ))
self.wfile.write(bytes())
self.wfile.write(bytes("</body></html>", "utf-8"))
字符串
下面这一部分是我想验证我对代码的理解的部分。我认为这里逻辑上发生了什么,代码中的注解中包含了一些额外的问题。
def do_POST(self):
content_length = int(self.headers['Content-Length'])
#The content-string above is an html header responsible for declaring the length of the text being passed to the server via the POST method.
#However, Content-Length is never declared a value that I can tell, not here or in the rest of the program. So, does HTML then by default take the entire doccument provided by the POST method if Content-Lengtg is not assigned any value?
# It is then coerced into an int and passed to the content_length variable. But what is the purpose of the ".headers" method?
post_data = self.rfile.read(content_length).decode('utf-8')
#utf-8 is the unicode format for encoding/decoding the given text. .read is being passed the length of the message and thus is reading the entire message. The message is then passed to .rfile, I am not sure why this is, why is the standard .read method not sufficent?
user_input = post_data.split('=')[1]
#I really have no idea why this the split method is needed at all. Could post_data not be used as it is?
self.send_response(200)
#Sends the webpage the 200 response code indicating the server proccessed the request correctly.
self.send_header('Content-type', 'text/html')
#Declares that the data about to be sent is of the type text, and is written in HTMl
self.end_headers()
self.wfile.write(bytes("html>head>title>https://pythonbasics.org</title>/head>", "utf-8"))
#I don't understand the use of the bytes class in these lines. I'm assuming that html needs information passed to it to be encoded into bytes for the transfer? This class does so?
self.wfile.write(bytes("<body>", "utf-8"))
self.wfile.write(bytes(f"<p>Hello {user_input}!</p>", "utf-8"))
#At the beginning of this string after the bytes class ther is a single "f" present. Why is this? Is it something to do with html coding or python? Also am I right in thinking that {user_input} is the syntax in HTML for inserting a variable?
self.wfile.write(bytes("</body></html>", "utf-8"))
型
2条答案
按热度按时间t5fffqht1#
作为一名软件开发人员,你要开发的许多东西之一就是尝试事物的能力。可能发生的最糟糕的事情是什么?错误,到处都是错误(如果你得到参考,请用巴斯光年的声音阅读它)。
我们喜欢遇到bug和错误吗?嗯,通常不是......但我们也不总是悲伤。错误是一个学习的机会,可以通过清理代码,创建有用的日志,了解新的软件包功能等来学习。
我的观点是:不要害怕测试。如果你面对别人的代码,你不确定某些东西是做什么的,或者为什么它会在那里,不要害怕删除它并重新编译代码!
例如.
另一个有用的功能是搜索和阅读软件包文档。是的,有时候这很无聊,但在大多数情况下,它会保存你的一天,甚至教你一两个新东西。
例如.
(提示:如果你不理解 * 继承 * 的概念,也许你应该后退一步,在深入研究像这个web服务器这样的例子之前,加强一下面向对象编程的概念。
当从一个已经编码的类继承时,查看文档总是一个好主意。我将为您保存几次点击并直接将链接放在这里。
在那里你可以找到关于属性
wfile
的信息。据说,wfile
包含用于将响应写回客户端的输出流。在写入此流时必须正确遵守HTTP协议,以便成功实现与HTTP客户端的互操作。
文档实际上是将我们重定向到另一个文档,这很好。这种情况经常发生。我们现在需要知道什么是“io.BufferedIOBase流”。或者,更具体地说,我们需要知道它的
write
方法是做什么的。文档非常简单,给予我们第一句话的答案:
write(B,/)
写入给定的字节类对象b,并返回写入的字节数(总是等于b的字节长度,因为如果写入失败,将引发OSError)。
这个难题已经解决了。
write
方法需要一个“类似字节”的对象作为输入,这就是为什么我们在调用self.wfile.write
时使用bytes
的原因。这两项技能(测试和阅读文档)是您更好地理解软件开发世界中的工作方式的核心工具。我觉得在回答您的具体问题之前,给予这些背景知识是很重要的。但是现在让我们开始吧
为什么需要
split
?我也会花一些时间来给予你一些其他主题的概述。我不是Maven,但希望你会觉得这很有趣。
使用HTTP表单时,了解用户传递的信息如何发送到服务器是很有用的。为此,您可以运行服务器代码,通过任何浏览器访问其页面链接,然后打开“devtools”(请查看如何在this link上执行此操作)。最后,打开“Network”选项卡
你会看到它一开始是空的,但随后就测试你的代码:输入你的名字并点击按钮。现在,可能出现了一些请求。
查找POST请求,因为它是按钮单击事件调用的请求。我们怎么知道呢?在您的代码中,
<form>
标记有以下选项<form action="/" method="post">
,它表示服务器在单击按钮时运行POST类型的方法。选择POST请求后,查找它的头。它有很多头,但现在只有一个有用:“Content-Type”。它说明了用户输入的数据将如何写入请求中。请参阅下面的打印屏幕
x1c 0d1x的数据
application/x-www-form-urlencoded
声明我们将以名称-值对的形式写入信息,如name1=value1&name2=value2&name3=value3
等(SO上有一些答案谈到了这一点,如this one)这开始敲响警钟,不是吗?但让我们深入一些。您可以在“Payload”选项卡上看到发送到服务器的实际信息。我也为您打印了它
的
你可以猜到我写了一个
X
并点击了按钮。但是看,这是浏览器发送的信息。属性的名称是“name”,因为表单的label
标签中有一个选项。如果你把它改成类似<label for="banana">
的东西,我们就会在浏览器中看到banana=X
。这就是浏览器如何将信息发送到服务器。从服务器端,您需要以某种方式读取它。这是通过
rfile.read
方法实现的。现在你知道了文档的路径,你会明白这个方法需要一个整数来表示要读取的字节数。令人高兴的是,这个字节数是在请求头中的“Content-Length”键下发送的。
你可以在第一次打印时检查一下,在我的例子中,“Content-Length”是6:属性的名称(
name
)是4个字节长;=
符号是1个字节长;我的答案(X
)也是1个字节长。这就是为什么Content-Length是6。现在你可能已经把一切都弄清楚了:
content_length
变量来获取POST有效负载的大小(以字节数为单位=
分隔的“名称/值”对的信息"Hello {user_answer}"
,你只需要值,所以你split
有效负载name=user_answer
和 voilà。这是一个相当长的解释“为什么”代码是这样写的。我经常享受这种阅读文档的旅程,但它可能会很无聊,我知道。
另一种理解“为什么”的方法是修改你的代码,打印整个
post_data
,然后你会看到name=answer
被打印出来,你可能会自己弄清楚一切。我希望你已经学到了一两件事。如果你喜欢,可以随意询问更多。祝你编码愉快(:
bxjv4tth2#
原因是因为post_data变量包含“name=<the_text_input>“,那么如果你想要文本输入值;你必须拆分字符串并获得最后一部分。