Jump to content
foobar123

Problem: Ajax -requests getting 301 redirects

Recommended Posts

Hello,

I have a problem with all AJAX -requests getting 301 redirect. AFAIK this leads to the POST -data sent with the request getting cleared.

Below I is an example about what I'm trying to do.

My question is:

  • Is there something I don't understand about Processwire or internet technology which is causing this behaviour?
  1. I have page with a button.
  2. When you click this button, an HTML overlay popup (done with Foundation and Reveal) with option to enter email is displayed
    • (The content of this popup is a processwire template which is loaded with AJAX -request. Causes also 301 redirect, but this doesn't use POST -data, so I didn't realise the problem at this point)
  3. Then this data is sent as POST -request with payload to processwire for processing
  4. The processing is done by special API -template, which exists solely for this purpose of processing data.
  5. However the payload in the POST -request never reaches the API -template
  6. I believe this is because a 301 redirect happens before the the POST -request reaches the API -template

Thanks for reading and special thanks for any answers!

Example code:

Popup (HTML & JavaScript):

<!-- use onsubmit to override the standard 'sending form to self' -behaviour
<form onsubmit="WEBSITE.dialog.download.mail($('#email').val(), event); ">
   <label>email:</label>
   <input id='email' name='email' type='email' value=''>
   <input type="submit" value="Send">
</from>

The function which sends the POST -request to processwire template (which processes  API requests) (the function is in separate .js file)

// I've translated this from CoffeeScript to JS without testing, hope there's no errors 

dialog = {
 download: {
   mail: function (email, ev){

     // Prevent default behaviour of submit -functionality
     ev.preventDefault(); 
     
     // Success and error callbacks
     success = function(response){
        console.log('success', response);
     }
     error = function(response){
        console.log('error', response);
     }

     // Do ajax -request with jQuery
     request = $.ajax({
       url: '/api/mailer/send/',
       method: "POST",
       data: {email: email},
       success: success,
       error: error
     });
  }
 }
}

I've also tried this with doing the request without jQuery, but result is the same.

 

The API template (PHP):

?php

  // Redirect non-ajax calls
  
  // Get the API address from url
  $api_url = explode('/api/', $page->url);

  if(!isset($api_url[1])){
    // This url is not in correct format, send error
    die(createJSONResponseError(
        1,
        'Invalid url format.'
      )
    );
  }

  switch ($api_url[1]):

    case 'mailer/send/':

      // This is where it stops every time, though I've checked from Chrome dev console that the email key/value pair exists (at least when request is made)
      if($input->post->email === null){
         die(createJSONResponseError(
             2,
             'Insufficient params.'
           )
         );
      }else{
        // Create the response
        $response = createJSONResponse(
          'success', 
           null
        );
      }
      break;

    // Default action - needs to be last of the list
    default:
      // So this api does not exist, send error
      die(createJSONResponseError(
          1,
          'Unknown API.'
        )
      );
      break;

  endswitch;

  // Send the response
  die($response);

?>

Here's how the responses are created (from a helper methods file):

/**
* Create JSON response for httpXMLRequest
*
* @param status - a string that represents the status of this operation. Recommended values: 'success' or 'error'
* @param result - the data resulting this request.
*
* @return JSON object
*
*/
function createJSONResponse($status, $result){
  return json_encode(
    array(
      'status' => $status,
      'result' => $result
    )
  );
}

/**
* Create JSON error response for httpXMLRequest
*
* @param code - error code
* @param msg - error message
*
* @return JSON object
*
*/
function createJSONResponseError($code, $msg){
  return createJSONResponse(
    'error', 
     array(
      'code' => $code,
      'msg' => $msg
      )
  );
}

Share this post


Link to post
Share on other sites

It seems you're missing a single-quote in your onsubmit attribute. 

I checked this and it seems this happened while transferring the example to forums: the quote is there in the original source.

Edited this mistake from the first post.

Share this post


Link to post
Share on other sites

What is your slash setting on the template? If you have no trailing slash turned on it would get redirected from domain/url/ to domain/url — and as you have trailing slash in the JS, it could be that you've turned it off.

(also, it seems you're using input segments. Those have have the trailing slash setting as well)

Share this post


Link to post
Share on other sites

What is your slash setting on the template?

"Should page URLs end with a slash?" is set to "Yes".

(also, it seems you're using input segments. Those have have the trailing slash setting as well)

Actually I have page structure to reflect the structure of the api. The "Allow URL Segments?" -setting is set to "No".

Share this post


Link to post
Share on other sites

So I found  the reason behind redirects:

  1. I'm using the multilanguage version of Processwire, and it adds the language id to URLs (e.g mysite/en/page/)
  2. My request URLs didn't have this language string in them (e.g mysite/page/) which caused them to be 301 redirected

I was able to find this out by using this plugin, which gives more detailed information about headers than Chrome dev tools (redirects are not bundled into one entry):

https://chrome.google.com/webstore/detail/live-http-headers/iaiioopjkcekapmldfgbebdclcnpgnlo

Thanks for the help I received

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By ICF Church
      Hi 👋
      Anyone else having this problem?
      Requirements:
      - Repeater (matrix & normal) with mutlilanguage fields (text, textarea…) 
      - Backend language set to something other than default (ie. German) 
      Reproduce:
      - Add a new repeater Item (ajax, I found no way to possible to disable it with matrix)

      (Notice how the default language tab is active instead of the backend language…)
      - Write something into the (default language) field
      - Try to save, if field is required, this will not work. If not required, then when reloading, the content will be inside the backend language field, instead of the default language field who was (presumably) active
      Analysis:
      When  loading  a new repeater element with ajax, the default langue tab is active, but the backend language inputfield is visible (with no visual indication). When writing into the field, it will populate the backend language. When manually clicking on the default language tab (which is already active), the field will switch to the actual default language field (which is [now] empty) (that can now be populated…)
      Also Notice, the labels of the elements to be added are in default language as well instead of the translated label (images instead of Bilder)…
      ProcessWire 3.0.148, Profields 0.0.5…
      Is it my system configuration, or does anyone else have the same issue? This is a screen recording of the problem:
      Issue: https://github.com/processwire/processwire-issues/issues/1179

      Screen Recording 2020-02-25 at 14.18.31.mov
    • By michelangelo
      Hello there,
      I am building my website, which has a dozen projects with 10 images each. Basically, I need a filtering system but built in the most efficient and user-friendly way. You can see below that the images flow sideways so being hidden, JS lazy loading was a good tool, but I just wanted to try AJAX. Is it fit for this purpose or it's more for dynamic content?
       

    • By louisstephens
      I have been messing around with creating pages from ajax requests, and it has gone swimmingly thus far. However, I am really struggling with creating a page and saving an image via ajax. 
      The form:
      <form action="./" role="form" method="post" enctype="multipart/form-data"> <div> <input type="text" id="preview" name="preview" placeholder="Image Title"> </div> <div> <input type="file" id="preview-name" name="preview-name"> </div> <div> <select id="select-tags" name="select-tags"> <?php $tags = $pages->find("template=tag"); ?> <option value="">Select Your Tags</option> <?php foreach ($tags as $tag) : ?> <option value="<?= $tag->name; ?>"><?= $tag->name; ?></option> <?php endforeach; ?> </select> </div> <div> <button type="button" id="submit-preview" name="submit" class="">Upload Images</button> </div> </form>  
      The ajax in my home template:
      $('#submit-preview').click(function(e) { e.preventDefault(); title = $("#preview").val(); image = $("input[name=preview-name]"); console.log(title); console.log(image); data = { title: title, image: image //not sure if this is actually needed }; $.ajax({ type: 'POST', data: data, url: '/development/upload-preview/', success: function(data) { console.log("Woo"); }, error: function(xhr, ajaxOptions, thrownError) { alert(xhr.responseText); } }); }); And finally in my ajax template:
      $imagePath = $config->paths->assets . "files/pdfs/"; //was from an older iteration $title = $sanitizer->text($_POST['title']); $image = $sanitizer->text($_POST['image']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->save(); $p->setOutputFormatting(false); $u = new WireUpload('preview_image'); $u->setMaxFiles(1); $u->setOverwrite(false); $u->setDestinationPath($p->preview_image->path()); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png', 'pdf')); foreach($u->execute() as $filename) { $p->preview_image->add($filename); } $p->save(); I can complete the file upload but just using a simple post to the same page and it it works well, but I was really trying to work out the ajax on this so I could utilize some modals for success on creation (and to keep my templates a little cleaner). When I do run the code I have, a new/blank folder is created under assets, and a new page is created with the correct title entered. However, no image is being processed. I do get a 200 status in my console. I have searched google for help, but everything seems to be slightly off from my needs. If anyone could help point me in the right direction I would greatly appreciate it. 
    • By louisstephens
      So I am using ajax to upload an image, but I am getting the error "Method WireUpload:: save does not exist or is not callable". I am not quite sure how to go about fixing this (at the moment).
      elseif($config->ajax && $input->urlSegment1 == "upload-preview") { $u = $config->paths->assets . "files/pdfs/"; $title = $sanitizer->text($_POST['title']); $p = new Page(); $p->template = "preview"; $p->parent = $pages->get("/previews/"); $p->name = $title; $p->title = $title; $p->save(); $p->setOutputFormatting(false); $u = new WireUpload('preview_image'); $u->setMaxFiles(1); $u->setOverwrite(false); $u->setDestinationPath($p->preview_image->path()); $u->setValidExtensions(array('jpg', 'jpeg', 'gif', 'png', 'pdf')); foreach($u->execute() as $filename) { $p->preview_image->add($filename); } $u->save(); } I compared my code to something I did previously (though previously I just posted to the current template file, not through ajax) which works, but this doesnt seem to be working. I have the _init.php file prepending as well. Does anyone have any ideas of what might be happening?
    • By Brian Scramlin
      I just wanted to share that I added an AJAX-powered gallery to an artist website that I developed and host: https://jackpinecreations.com/gallery/

      There were two things that frustrated me about creating this. Perhaps you can show me a better way.
      1. After creating my processing script, which I placed under /templates/scripts/get-items.php, I realized that I would get a 403, due to ProcessWire's routing and security. This forced me to have to create a template and page for this little script. This was frustrating simply because it seemed unnecessarily confusing. But worse, see #2.
      2. I usually use config.php to prepend and append each of my templates with a head.inc and foot.inc, which keeps my templates easy to use and I don't have to go and use the GUI to do so on each template separately. However, since I realized I needed to create a new template and page so as to access it, whenever I sent POST params to it, I would get the header and footer along with it!!! I could find no workarounds and had to remove the pre/append calls in config.php and use the GUI on each template individually.  
      Code Below if you're interested:
      HTML and JavaScript (forgive my sad JavaScript skills, I know this can be tightened up)
      <!-- Begin Grid --> <div class="container mt-4"> <div id="gallery" class="row"> <?php foreach ($page->children("limit=9") as $child): ?> <div class="col-6 col-md-4 gallery-item"> <a href="<?= $child->url ?>" title="View <?= $child->title ?>"> <img class="gallery-item" src="<?= $child->item_featured_image->size(640, 640)->url ?>" alt="<?= $child->title ?> Image"> </a> </div> <?php endforeach; ?> </div> </div> <!-- End Grid --> <div class="center-block text-center"> <button id="get-more-items" type="button" name="get-more-items" class="btn-vintage">Load More</button> </div> <script type="text/javascript"> var buttonGetItems = document.getElementById("get-more-items"); var indexStart = 0; buttonGetItems.addEventListener("click", function() { indexStart += 9; $.ajax({ url: '<?= $pages->get(1186)->url ?>', type: "POST", dataType:'json', // add json datatype to get json data: ({page_id: <?= $page->id ?>, index_start: indexStart}), success: function(data){ console.log(data); if (data[1]) { //for each element, append it. $.each(data, function(key, value) { $("#gallery").append(value); }); } else { $("#get-more-items").after('<p class="center-block text-center">There are no more items to load.</p>'); $("#get-more-items").remove(); } } }); }); </script> Processing Script
      <?php $items_array = []; $i = 0; foreach ($pages->get($input->post->page_id)->children->slice($input->post->index_start, 9) as $child) { $i++; $items_array[$i] = "<div class='col-6 col-md-4 gallery-item'> <a href='$child->url' title='View $child->title'> <img src='{$child->item_featured_image->size(640,640)->url}' alt='$child->title Image'> </a> </div>"; } echo json_encode($items_array); I love ProcessWire for hundreds of reasons, but I've been using AJAX more and more, and I'm not liking having to create templates to access scripts. 
      Any advice?
×
×
  • Create New...