CakePHP ajax post keeps returning 400 Bad Request

前端 未结 4 596
北海茫月
北海茫月 2021-02-09 19:41

I am tring to use an ajax post to an action. GET requests work fine but when I try to POST I see a \'400 Bad Request\' in firebug and the view return a \'Black hole\' response.<

相关标签:
4条回答
  • 2021-02-09 19:49

    FYI CakePHP 2.3 and above now includes unlockedActions just for this purpose to be used in beforeFilter in your controller, or AppController.

    $this->Security->unlockedActions = array('ajaxAction');
    

    From: http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#disabling-security-component-for-specific-actions

    0 讨论(0)
  • 2021-02-09 20:05

    Make shure you are putting the function editUser in:

      public function beforeFilter(){
        parent::beforeFilter()
        $this->Auth->allow('editUser');
        }
    

    inside of UsersController,

    Regards

    0 讨论(0)
  • 2021-02-09 20:05

    Joseph's answer was missing one detail for me. My form and ajax call was in index.ctp and was calling /controller/edit.ctp so my $this->Form->create call needed 'action'=>'/controller/edit' added to it.

    0 讨论(0)
  • 2021-02-09 20:06

    Protection against form tampering is one of the basic features provided by the Security Component. As long as it is enabled, it is going to treat all POSTs as form submissions.

    A regular hand-coded HTML form won't work with the Security Component enabled, so neither will a JQuery-generated POST. You can, of course, use $this->Security->validatePost = false; or $this->Security->csrfCheck = false; but then you loose the protection that the Security Component provides.

    To keep the Security Component on and working as normal, you need to use the CakePHP Form Helper to create the form you're going to post via ajax. This way the data[_Token][fields] and data[_Token][unlocked] hidden fields get generated with their keys:

    <?php 
        echo $this->Form->create('Test',array('id'=>'testform'));
        echo $this->Form->input('Something');
        echo $this->Form->submit();
        echo $this->Form->end();
    ?> 
    

    This will generate something like this:

    <form action="/your/url" id="testform" method="post" accept-charset="utf-8">
        <div style="display:none;">
            <input type="hidden" name="_method" value="POST"/>
            <input type="hidden" name="data[_Token][key]" value="9704aa0281d8b5a2fcf628e9fe6f6c8410d8f07a" id="Token937294161"/>
        </div>
        <div class="input text">
            <input name="data[Test][Something]" class="required" type="text" id="TestSomething"/>
        </div>
        <div class="submit">
            <input  type="submit" />
        </div>
        <div style="display:none;">
            <input type="hidden" name="data[_Token][fields]" value="0c81fda1883cf8f8b8ab39eb15d355eabcfee7a9%3A" id="TokenFields817327064"/>
            <input type="hidden" name="data[_Token][unlocked]" value="" id="TokenUnlocked281911782"/>
        </div>
    </form>   
    

    Now it's just a matter of serializing this form in JQuery so that it can be sent with the ajax POST:

        $('#testform').submit(function(event) {
            $.ajax({
                type: 'POST',
                url: "/your/url",
                data: $('#testform').serialize(),
                success: function(data){ 
                    alert('Wow this actually worked');
                },
                error:function() {
                    alert('This will never work');
                }
            });
            event.preventDefault(); // Stops form being submitted in traditional way
        });
    

    Now if you press the submit button, the POST will succeed.

    IMPORTANT: Due to the fact that the Form Helper's Tokens can only be used with the Security Component once, this solution only works if you only intend to POST once per page generation. If you need to be able to post the same form several times between page reloads then you'll need to do the following when you add the Security Component at the beginning of your Controller:

    public $components = array(
        'Security' => array(
            'csrfUseOnce' => false
        )
    );
    

    ...this will allow the tokens to be used for more than one request. It's not as secure but you can combine it with csrfExpires so that the tokens will expire eventually. This is all documented in the CSRF configuration section of the Cake book.

    0 讨论(0)
提交回复
热议问题