在请求上下文之外工作 尝试使用 BottlePy 提交表单时出错

Working outside of request context Error while trying to submit a form, using BottlePy

我正在学习 Python 并尝试通过简单的 HTML 表单发送带有 Python 的电子邮件。主要问题是提交表单,因为smtp邮件设置100%没问题

这是我的 Python 代码:

@post("/sendemail")
def sendemail():
    name = request.forms.get('name')
    subject = request.forms.get('Subject')
    email = request.forms.get('_replyto')
    message = request.forms.get('message')

    your_email = "testmail@gmail.com"
    your_password = "pass"

    # Logging in to our email account
    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.ehlo()
    server.starttls()
    server.login(your_email, your_password)

    # Sender's and Receiver's email address
    sender_email = "testmail@gmail.com"
    receiver_email = "testmail@gmail.com"

    msg = EmailMessage()
    msg.set_content(
        "First Name : " + str(name) + "\nEmail : " + str(email) +
        "\nSubject : " + str(subject) + "\nMessage : " + str(message))
    msg['Subject'] = 'New Response'
    msg['From'] = sender_email
    msg['To'] = receiver_email
    # Send the message via our own SMTP server.
    try:
        # sending an email
        server.send_message(msg)
    except EmailMessage.DoesNotExist:
        pass

    return redirect('/', code=None)

<form action="/sendemail" method="post">
    <input type="text" name="name" placeholder="Name" required="required"/><br/><br/>
    <input type="text" name="Subject" placeholder="Subject" required="required"/><br/><br/>
    <input type="email" name="_replyto" placeholder="E-mail" required="required"/><br/><br/>
    <textarea name="message" placeholder="Your Message" required="required"></textarea><br/><br/>
<br/><br/>
    <button class="btn btn-primary" type="submit">Send</button>
</form>

提交电子邮件表单时出现以下错误。我正在使用 BottlePy。

127.0.0.1 - - [02/Feb/2022 12:57:42] "GET / HTTP/1.1" 200 18483
Traceback (most recent call last):
  File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\bottle.py", line 868, in _handle
    return route.call(**args)
  File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\bottle.py", line 1748, in wrapper
    rv = callback(*a, **ka)
  File "E:\Python\Day_82_Assignment_2_&_3\Engine\src\server.py", line 114, in sendemail
    name = request.forms.get('name')
  File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\werkzeug\local.py", line 432, in __get__
    obj = instance._get_current_object()
  File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\werkzeug\local.py", line 554, in _get_current_object
    return self.__local()  # type: ignore
  File "C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\globals.py", line 33, in _lookup_req_object
    raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.
127.0.0.1 - - [02/Feb/2022 12:57:49] "POST /sendemail HTTP/1.1" 500 750

如果问题是新手,我很抱歉。请帮忙!

好的,所以我设法找到了我的问题所在。关键就在这行代码:

return redirect('/', code=None)

我已经改成:

return template(absolute_path + "/templates/index.html")

因此,使用 BottlePy 发送电子邮件的工作代码是:

get_cwd = str(Path().absolute())
absolute_path = get_cwd.replace('templates', 'test_files')


@route("/")
def index():
    print(absolute_path)
    return template(absolute_path + "/templates/index.html")


@route("/sendemail", method='POST')
def form():
    name = request.forms.get("name")
    subject = request.forms.get("subject")
    reply_to = request.forms.get("reply_to")
    message = request.forms.get("message")

    send_from = "test@gmail.com"
    send_to = "test@gmail.com"

    msg = EmailMessage()
    msg.set_content(f"Hello, my name is: {name}\n {message}\n\n "
                    f"You can further contact me at this email address: {reply_to}")
    msg["Subject"] = subject
    msg["From"] = send_from
    msg["To"] = send_to

    server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    server.ehlo()
    server.login("test@gmail.com", "test")
    server.send_message(msg)

    server.quit()

    return template(absolute_path + "/templates/index.html")
    # return template("index.html")


run(host='127.0.0.1', port=9090, debug=True)

Bottle Py 主要处理像我这样的案例的返回模板。他们的文档对我帮助很大。案件结案!

我很确定问题有所不同,您的新代码,尤其是您对 return redirect('/', code=None) 行更改的假设是不正确的。

您最初获得的异常回溯确实说明了它的含义: “在请求上下文之外工作”。如您所见,此异常是由烧瓶引发的。但是正如你所说,你使用瓶子。

这让我想到你为 request 使用了错误的导入的理论 类似于 from flask import request 而不是 from bottle import request。在编辑器有自动导入功能的时候,可能会出现这种情况。

为了确保我尝试重现您的问题。但是没有邮件的东西,我们可以通过阅读回溯来非常确定这不会导致你的问题。

因此我创建了这个简单的文件结构:

.
├── app.py
└── templates
    └── index.html

index.html

的内容
<html>
<body>
    <form action="/sendemail" method="post">
        <input type="text" name="name" placeholder="Name" required="required"/><br/><br/>
        <input type="text" name="Subject" placeholder="Subject" required="required"/><br/><br/>
        <input type="email" name="_replyto" placeholder="E-mail" required="required"/><br/><br/>
        <textarea name="message" placeholder="Your Message" required="required"></textarea><br/><br/>
    <br/><br/>
        <button class="btn btn-primary" type="submit">Send</button>
    </form>
</body>
</html>

用于测试此错误的 app.py 内容不会在正确导入时发生

from pathlib import Path

from bottle import route, redirect, run, post, template, request 

get_cwd = str(Path().absolute())
absolute_path = get_cwd.replace('templates', 'test_files')


@route("/")
def index():
    print(absolute_path)
    return template(absolute_path + "/templates/index.html")

@post("/sendemail")
def sendemail():
    name = request.forms.get('name')
    subject = request.forms.get('Subject')
    email = request.forms.get('_replyto')
    message = request.forms.get('message')

    your_email = "testmail@gmail.com"
    your_password = "pass"

    # Logging in to our email account
    # server = smtplib.SMTP('smtp.gmail.com', 587)
    # server.ehlo()
    # server.starttls()
    # server.login(your_email, your_password)

    # Sender's and Receiver's email address
    sender_email = "testmail@gmail.com"
    receiver_email = "testmail@gmail.com"

    # msg = EmailMessage()
    # msg.set_content(
    #     "First Name : " + str(name) + "\nEmail : " + str(email) +
    #     "\nSubject : " + str(subject) + "\nMessage : " + str(message))
    # msg['Subject'] = 'New Response'
    # msg['From'] = sender_email
    # msg['To'] = receiver_email
    # # Send the message via our own SMTP server.
    # try:
    #     # sending an email
    #     server.send_message(msg)
    # except EmailMessage.DoesNotExist:
    #     pass

    return redirect('/', code=None)


run(host='0.0.0.0', port=9090, debug=True)

python app.py 按预期启动应用程序。该网站也按预期显示,并在提交时使用正确的表单值,我再次被重定向到表单。

所以我将 app.py 更改为从 flask 导入请求。

from pathlib import Path

from bottle import route, redirect, run, post, template
from flask import request

get_cwd = str(Path().absolute())
absolute_path = get_cwd.replace('templates', 'test_files')


@route("/")
def index():
    print(absolute_path)
    return template(absolute_path + "/templates/index.html")

@post("/sendemail")
def sendemail():
    name = request.forms.get('name')
    subject = request.forms.get('Subject')
    email = request.forms.get('_replyto')
    message = request.forms.get('message')

    your_email = "testmail@gmail.com"
    your_password = "pass"

    # Logging in to our email account
    # server = smtplib.SMTP('smtp.gmail.com', 587)
    # server.ehlo()
    # server.starttls()
    # server.login(your_email, your_password)

    # Sender's and Receiver's email address
    sender_email = "testmail@gmail.com"
    receiver_email = "testmail@gmail.com"

    # msg = EmailMessage()
    # msg.set_content(
    #     "First Name : " + str(name) + "\nEmail : " + str(email) +
    #     "\nSubject : " + str(subject) + "\nMessage : " + str(message))
    # msg['Subject'] = 'New Response'
    # msg['From'] = sender_email
    # msg['To'] = receiver_email
    # # Send the message via our own SMTP server.
    # try:
    #     # sending an email
    #     server.send_message(msg)
    # except EmailMessage.DoesNotExist:
    #     pass

    return redirect('/', code=None)


run(host='0.0.0.0', port=9090, debug=True)

这次我在提交表单时得到了预期的回溯:

Traceback (most recent call last):
  File "/home/lobi/Whosebug/bottlepy_mail/venv/lib/python3.8/site-packages/bottle.py", line 868, in _handle
    return route.call(**args)
  File "/home/lobi/Whosebug/bottlepy_mail/venv/lib/python3.8/site-packages/bottle.py", line 1748, in wrapper
    rv = callback(*a, **ka)
  File "app.py", line 17, in sendemail
    name = request.forms.get('name')
  File "/home/lobi/Whosebug/bottlepy_mail/venv/lib/python3.8/site-packages/werkzeug/local.py", line 432, in __get__
    obj = instance._get_current_object()
  File "/home/lobi/Whosebug/bottlepy_mail/venv/lib/python3.8/site-packages/werkzeug/local.py", line 554, in _get_current_object
    return self.__local()  # type: ignore
  File "/home/lobi/Whosebug/bottlepy_mail/venv/lib/python3.8/site-packages/flask/globals.py", line 33, in _lookup_req_object
    raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

与 OP 回溯唯一明显不同的是它显示了我为此使用的 virtualenv 的路径。

所以你最初的方法很好。

尽管如此,我还是要告诉您如何避免落入此类陷阱。 由于您依赖许多瓶装进口产品,我只会 import bottle

现在使用的名字很明显来自瓶子:

from pathlib import Path

import bottle

get_cwd = str(Path().absolute())
absolute_path = get_cwd.replace('templates', 'test_files')


@bottle.route("/")
def index():
    print(absolute_path)
    return bottle.template(absolute_path + "/templates/index.html")

@bottle.post("/sendemail")
def sendemail():
    name = bottle.request.forms.get('name')
    subject = bottle.request.forms.get('Subject')
    email = bottle.request.forms.get('_replyto')
    message = bottle.request.forms.get('message')

    your_email = "testmail@gmail.com"
    your_password = "pass"

    # Logging in to our email account
    # server = smtplib.SMTP('smtp.gmail.com', 587)
    # server.ehlo()
    # server.starttls()
    # server.login(your_email, your_password)

    # Sender's and Receiver's email address
    sender_email = "testmail@gmail.com"
    receiver_email = "testmail@gmail.com"

    # msg = EmailMessage()
    # msg.set_content(
    #     "First Name : " + str(name) + "\nEmail : " + str(email) +
    #     "\nSubject : " + str(subject) + "\nMessage : " + str(message))
    # msg['Subject'] = 'New Response'
    # msg['From'] = sender_email
    # msg['To'] = receiver_email
    # # Send the message via our own SMTP server.
    # try:
    #     # sending an email
    #     server.send_message(msg)
    # except EmailMessage.DoesNotExist:
    #     pass

    return bottle.redirect('/', code=None)


bottle.run(host='0.0.0.0', port=9090, debug=True)