简体   繁体   English

Django QueryDict为空,带有request.POST但在request.GET中填充

[英]Django QueryDict empty with request.POST but populated in request.GET

Short version : On a django site, I can grab values from request.GET but not request.POST in response to a request from Twilio. 短版 :在Django的网站,我可以抓住的值request.GET ,但不request.POST响应来自Twilio的请求。 I suspect it has something to do with csrf, but I'm not really sure how to debug the problem. 我怀疑它与csrf有关,但我不确定如何调试问题。 Details below. 详情如下。

Long version: I am helping a friend with a project where we are running a medical survey over SMS using the Twilio REST API. 长版:我正在帮助一个朋友进行一个项目,我们正在使用Twilio REST API对SMS进行医学调查。 I had a domain and a very bare-bones django-built site on that domain, which I had built really just to better familiarize myself with django, so we're using that. 我在该域上有一个域和一个非常简单的django构建的站点,我构建的只是为了更好地熟悉django,所以我们正在使用它。

We're collecting SMS responses to our survey and as part of the Twilio API, it sends any response to our number to a url specified under the account, so we have the response targeting something like the following: 我们正在收集对我们调查的短信回复,并且作为Twilio API的一部分,它会将我们号码的任何回复发送到帐户下指定的网址,因此我们的响应定位如下:

...mydomain.com/some_page/another_page/

The Twilio request then looks something like the following: 然后,Twilio请求看起来如下所示:

...mydomain.com/some_page/another_page/?AccountSid=###SOME_LONG_ACCOUNT_SIDE&From=%2BPHONE_NUMBER&Body=bla+BLA+bla+BLA&SmsSid=##MESSAGE_ID_KEY&SmsMessageSid=##MESSAGE_ID_KEY&FromCity=Santa+Cruz&FromState=California...

Working Code 工作守则

I am testing that the incoming request has our AccountSid inside it (compared with the value in the database) and in my views.py for the app, I have something that looks like the following (and this works): 我正在测试传入的请求里面有我们的AccountSid (与数据库中的值相比)和我的views.py中的应用程序,我有一些看起来像下面的东西(这是有效的):

from our_app import TwilioAccount
our_account = TwilioAccount.objects.get(id=1)

def twilio_response(request):
    assert request.GET.get('AccountSid', None) == our_account.account_sid
    ## log the incoming request to the database under survey responses...

Non-Working Code 非工作守则

If I log-in to our Twilio account and switch the request method to POST , and then I switch all of my data collecting to request.POST , the above assert statement fails. 如果我登录到我们的Twilio帐户和申请方法切换到POST ,然后我转我的所有数据收集到的request.POST ,上述断言语句失败。 Further debugging reveals that my QueryDict is empty under POST, POST: {} , so there is no key value grabbed. 进一步调试显示我的QueryDict在POST, POST: {}下是空的,因此没有抓取键值。

I thought this maybe was because POST under django requires a csrf_token , but I figured checking for the AccountSid was fairly good, so I imported csrf_exempt and wrapped the above function with that: 我想这可能是因为django下的POST需要一个csrf_token ,但我认为检查AccountSid是相当不错的,所以我导入了csrf_exempt并将上面的函数包装起来:

@csrf_exempt
def twilio_response(request):
    assert request.POST.get('AccountSid', None) == our_account.account_sid
    ## log the incoming request to the database under survey responses...

AssertionError: ...

This does not work with the exact same request: the QueryDict is empty. 这不适用于完全相同的请求:QueryDict为空。


Questions: 问题:

1) Is there something else I need to do to make my @csrf_exempt work? 1)为了让我的@csrf_exempt工作,我还需要做些什么吗? Alternate question: is this a terrible and dumb way to do this ? 替代问题: 这是一种可怕而愚蠢的方式吗? How do people usually satisfy this requirement when working with other company's APIs and not actual, logged-in users? 在使用其他公司的API而不是实际的登录用户时,人们通常如何满足此要求?

1a) Instead of making it csrf_exempt, I could just keep it as a GET request, knowing that it's still checking all incoming requests against our account_sid. 1a)我可以将它作为GET请求保留,而不是使其成为csrf_exempt,因为它知道它仍在检查所有传入的请求,而不是我们的account_sid。 Should I do that or is that a really naive way to do it? 我应该这样做还是真的很天真的方式呢?

2) I am eager to learn the best way to do this: should I build a django form and then route the request to my form and test validity and clean the data that way? 2)我渴望学习这样做的最佳方法:我应该构建一个django表单然后将请求路由到我的表单并测试有效性并以这种方式清理数据吗? If so, can anyone give me a loose outline on what the view/form would look like (complete with csrf_token) when there's not going to be a template for the form? 如果是这样,任何人都可以给我一个关于视图/表单看起来像什么的宽松轮廓(完成csrf_token),而不是表格的模板?

Matt from the Twilio Developer Evangelist team here. 来自Twilio Developer Evangelist团队的马特来自这里。

1) Wrapping your twilio_response function with @csrf_exempt to remove the Django CSRF token check is the right way to go here. 1)用@csrf_exempt包装你的twilio_response函数来删除Django CSRF令牌检查是正确的方法。 Twilio does not generate a Django CSRF token. Twilio不会生成Django CSRF令牌。 Instead, there are other ways to validate POSTs are coming from Twilio, such as signature validation with the X-Twilio-Signature header. 相反,还有其他方法来验证来自Twilio的POST,例如使用X-Twilio-Signature标头进行签名验证。 See the Twilio security docs for details. 有关详细信息,请参阅Twilio安全文档

1a) Using the GET request is convenient for testing and debugging, but POST should be used in production. 1a)使用GET请求便于测试和调试,但POST应该用于生产。 GET requests do not have a body according to the HTTP spec, so the results are passed in the query string. 根据HTTP规范,GET请求没有正文,因此结果将在查询字符串中传递。 If the parameters are too large, for example with a text message that has a maximum length of 1600 characters, the query string in the URL could exceed the maximum length of a URL and potentially cause issues when you handle the string. 如果参数太大(例如,文本消息的最大长度为1600个字符),则URL中的查询字符串可能会超出URL的最大长度,并且在处理字符串时可能会导致问题。

2) Django forms are a good way to go for this use case, particularly a ModelForm that leverages your existing Model used to save the response. 2)Django表单是这个用例的好方法,特别是利用现有模型来保存响应的ModelForm。 For example, your ModelForm could look something like the following if you are saving your data to a TwilioMessage model: 例如,如果要将数据保存到TwilioMessage模型,则ModelForm可能类似于以下内容:

from django.forms import ModelForm
from .models import TwilioMessage


class MessageForm(ModelForm):
    pass

    class Meta:
        model = ReactionEvent
        # include all fields you're saving from the form here
        fields = ['body', 'to', 'from_', 'signature',] 

In my option,Have you open DEBUG(= True) in settings.py? 在我的选项中,您是否在settings.py中打开了DEBUG(= True)? And in the DEBUG mode, you can raise An Exception(raise Exception('')),And then you can see the Environment Varialbe like url, GET,POST.etc....in you page OR return HttpResponse(request.POST.dict()) to see the post variable. 在DEBUG模式下,您可以引发异常(引发异常('')),然后您可以在您的页面中看到环境Varialbe,如url,GET,POST.etc ....或者返回HttpResponse(request.POST) .dict())查看post变量。 use crsf_exempt is a right way when post 使用crsf_exempt是发布时的正确方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM