如何使用 python 从传入的 HTTP POST 中提取数据

How to extract data from incoming HTTP POST using python

我有一个 Ubuntu LAMP 网络服务器,数据通过 HTTP POST 方法不断发送到网络服务器。我需要从 HTTP POST 中提取数据并将它们插入到数据库中。我不知道该怎么做。有很多关于如何处理传出 HTTP POST 请求和传入 HTTP POST 请求的示例。我想编写一个 python3 脚本,它将从传入的 HTTP POST 请求中提取数据并将它们保存为变量,我将使用它来将数据插入数据库以及 return 响应client.Can 有人在这方面帮助我吗?

更新

根据您在下面发布的代码,这是一个有效的答案。

#!/usr/bin/python3
import socketserver
from http.server import BaseHTTPRequestHandler
import time
import threading


def do_something(site_id, first, last, pass1):
    print(site_id)
    print(first)
    print(last)
    print(pass1)
    #just to illustrate the point and print the variables


class MyHandler(BaseHTTPRequestHandler):
    def do_POST(self):    # !important to use 'do_POST' with Capital POST
        global site_id, first, last, pass1  #those are still undefined at the module level ;) remember this for later
        if self.path == '/do_something':

            request_headers = self.headers

            site_id = request_headers["m_site_name"]
            first = request_headers["m_first_name"]
            last = request_headers["m_last_name"]
            pass1 = request_headers["m_device_name"]

            do_something(site_id, first, last, pass1)
        self.send_response(200)
        self.end_headers()             #as of P3.3 this is required

try:
    httpd = socketserver.TCPServer(("localhost", 9001), MyHandler)
    httpd.serve_forever()
finally:
    httpd = socketserver.TCPServer(("localhost", 9001), MyHandler)
    httpd.server_close()

用 Postman 调用

命令行输出为

C:\Development\Python\test\venv\Scripts\python.exe C:/Development/Python/test/webserver_old.py
1001
jyoti0
127.0.0.1 - - [19/Nov/2018 21:53:45] "POST /do_something HTTP/1.1" 200 -
jyoti1
101

我在这里合并了这些答案: 参考 one, two and third 这也是非常重要的阅读: https://docs.python.org/3/library/http.server.html

http.server is not recommended for production. It only implements basic security checks.

我认为对于小型实施和一些测试或概念验证是可以的,但最终您需要更好地管理它,也许我可以建议您花一些时间并使用 Flask,是实际上是 Python API 构建和原型制作的优秀且非常轻巧的框架。

-

上一个答案(上面已弃用和更新)

-

根据对 this 的一个非常简单的参考:

def do_POST(self):
        # Doesn't do anything with posted data
        content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
        post_data = self.rfile.read(content_length) # <--- Gets the data itself
        self._set_headers()
        self.wfile.write("<html><body><h1>POST!</h1></body></html>")

更新(没有和 API):

假设您 运行 在自定义端口上或机器上,在 URL 处有自定义尾随部分,那么 "pure" python 将如下所示:

import SocketServer
from BaseHTTPServer import BaseHTTPRequestHandler

def doSomething():
    print "i did"

class MyHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path == '/doSomething':
            mail = self.request.POST.get('email')
            something = self.request.POST.get('something')

            doSomething()
        self.send_response(200)

httpd = SocketServer.TCPServer(("", 8080), MyHandler)
httpd.serve_forever()

我假设这样你可以自由地重用变量。另请查看此参考资料 ,Brenda 的回答。

@oetoni,我在使用时出现超时错误:

#!/usr/bin/python3
import socketserver
from http.server import BaseHTTPRequestHandler
import time
import threading


def do_something(site_id, first, last, pass1):
    print(site_id)
    print(first)
    print(last)
    print(pass1)
    #just to illustrate the point and print the variables


class MyHandler(BaseHTTPRequestHandler):
    def do_POST(self):    # !important to use 'do_POST' with Capital POST
        global site_id, first, last, pass1  #those are still undefined at the module level ;) remember this for later
        if self.path == '/do_something':

            request_headers = self.headers

            site_id = request_headers["m_site_name"]
            first = request_headers["m_first_name"]
            last = request_headers["m_last_name"]
            pass1 = request_headers["m_device_name"]

            do_something(site_id, first, last, pass1)
        self.send_response(200)
        self.end_headers()             #as of P3.3 this is required

try:
    httpd = socketserver.TCPServer(("localhost", 9001), MyHandler)
    httpd.serve_forever()
finally:
    httpd = socketserver.TCPServer(("localhost", 9001), MyHandler)
    httpd.server_close()

但是我在使用这段代码时得到了正确的响应:

#!/usr/bin/python3

# -*- coding: UTF-8 -*-

import cgi
import cgitb
cgitb.enable()

print('Content-Type: text/html')
print('')

arguments = cgi.FieldStorage()
for i in arguments.keys():
        print(arguments[i].value)

并在网络浏览器上打印接收到的数据。 我在 apache web 服务器上使用这个脚本作为 cgi 脚本,可以通过 web 浏览器访问它。我不是 运行 此脚本作为服务或应用程序。

#!/usr/bin/python3

# -*- coding: UTF-8 -*-

import cgi
import cgitb
cgitb.enable()

print('Content-Type: text/html\n')
arguments = cgi.FieldStorage()
print(arguments["m_site_name"].value)
print("<br />\n")
print(arguments["m_first_name"].value)
print("<br />\n")
print(arguments["m_last_name"].value)
print("<br />\n")
print(arguments["m_device_name"].value)
print("<br />\n")
site = arguments["m_site_name"].value
first = arguments["m_first_name"].value
last = arguments["m_last_name"].value
device = arguments["m_device_name"].value
-----do_other_things_with_the_variables(site,first,last,device)-----

这段代码解决了我的问题。现在我可以使用这个 python cgi 脚本将 HTTP POST 数据存储到变量中。

我的 HTTP POST 请求: http://your_server_url_or_IP/cgi-bin/python_script.py?m_site_name=MySite&m_first_name=anyname&m_last_name=anylastanme&m_device_name=anydeviceidorname

使用 python3,在处理程序 class 的 do_POST() 内基于 http.server.*Handler:

import cgi

enctype, attrs = cgi.parse_header(self.headers['Content-Type'])
if enctype == 'multipart/form-data':
    boundary = {'boundary':  attrs['boundary'].encode() }
    form_data = cgi.parse_multipart(self.rfile, boundary)
    file_content = form_data.get('myfile')
    fname = 'data/uploads/' + str(time.time()) + '.json'
    with open(fname, 'wb') as fp:
        for part in file_content:
            fp.write(part)

不要忘记插入内容长度检查以限制最大文件大小。 大概 cgi.FieldStorage 在达到 limit 字节时停止读取(如果指定)并且通常也能更好地处理大文件。这不是官方的一部分doc。我在源文件cgi.py.

中看到了