Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronous XHR request not supported, always yielding a 404 error #1384

Open
key88sf opened this issue May 13, 2024 · 13 comments
Open

Synchronous XHR request not supported, always yielding a 404 error #1384

key88sf opened this issue May 13, 2024 · 13 comments
Labels
Needs Triage [Type] Bug An existing feature does not function as intended
Milestone

Comments

@key88sf
Copy link

key88sf commented May 13, 2024

It looks like any calls by plugins to admin-ajax.php result in a 404 Not Found error when running inside a playground instance.

Is there any way to enable AJAX requests in the blueprint JSON?

@bgrgicak
Copy link
Collaborator

Is there any way to enable AJAX requests in the blueprint JSON?

Would you be able to provide an example blueprint to help us better understand your issue?

@adamziel adamziel added [Type] Bug An existing feature does not function as intended Needs Triage labels May 14, 2024
@adamziel adamziel added this to the Zero Crashes milestone May 14, 2024
@key88sf
Copy link
Author

key88sf commented May 14, 2024

@bgrgicak Yes - so I was testing with our plugin using this Blueprint JSON below (plugin name redacted here):

{
  "$schema": "https://playground.wordpress.net/blueprint-schema.json",
  "landingPage": "/wp-admin/index.php",
  "preferredVersions": {
    "php": "8.3",
    "wp": "latest"
  },
  "phpExtensionBundles": [
    "kitchen-sink"
  ],
  "features": {
    "networking": true
  },
  "steps": [
    {
      "step": "login",
      "username": "admin",
      "password": "password"
    },
    {
      "step": "installPlugin",
      "pluginZipFile": {
        "resource": "wordpress.org/plugins",
        "slug": "my-plugin-slug-name"
      },
      "options": {
        "activate": true
      }
    }
  ]
}

Our plugin calls admin-ajax.php on various pages, for example from the media library edit page. But in the Playground instance, this is giving a 404:

URL: /wp-admin/post.php?post=5&action=edit

Chrome console:
POST https://playground.wordpress.net/scope:0.9331797754628046/wp-admin/admin-ajax.php 404 (Not Found)

@bgrgicak
Copy link
Collaborator

Is there any way to enable AJAX requests in the blueprint JSON?

Ajax requests are enabled by default. You can see it by loading wp-admin in Playground and checking the network tab.

I assume that something else related to Playground is causing the issue for you.

If you can't share the plugin with us, you could debug it yourself by taking a look at the Playground logs (browser console, or click on View Logs in the upper right menu).

@key88sf
Copy link
Author

key88sf commented May 15, 2024

This is really strange -- the URL is exactly the same between what the plugin is posting to and what the wp-admin page is posting to.

The only difference I see is in some of the network headers. There are additional security headers which are sent when the plugin javascript makes the request (via jQuery.ajax()):

Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

This is the JS code which makes the call:

      jQuery.ajax({
        type: 'post',
        dataType: 'json',
        async: false,
        data: {
          'action': 'alax_check_image',
          'security': wp_alax.security_check_image,
          'attachment_id': attachmentId,
        },
        url: wp_alax.ajax_url, // this is set to: admin_url( 'admin-ajax.php' )
        success: function (response) {
          status = response.status;
        }
      });

Does that help at all?

@bgrgicak
Copy link
Collaborator

I don't think it's the security headers. I tried adding them to a heartbeat request and it kept working.

The code you provided doesn't work for me because I don't have the alax_check_image endpoint. Would you be able to provide instructions on how to recreate this in Playground? I would love to help, but first I need to be able to recreate the issue.

To debug it further you could rewrite the request to use fetch and see if this resolves the issue. If yes, compare the two requests to see what happened.

Example:

fetch(
wp.src.match(/(^[^\/]*\/\/[^\/]*\/[^\/]*)\/.*/)[1] +
    "/wp-admin/admin-ajax.php",
  {
    headers: {
      accept: "application/json, text/javascript, */*; q=0.01",
      "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
      "x-requested-with": "XMLHttpRequest",
        "Sec-Fetch-Dest": "empty",
        "Sec-Fetch-Mode": "cors",
        "Sec-Fetch-Site": "same-origin",
    },
    referrer:
      "https://playground.wordpress.net/scope:0.8893762696707332/wp-admin/edit-comments.php",
    referrerPolicy: "strict-origin-when-cross-origin",
    body: "interval=60&_nonce=1c0d4e2483&action=heartbeat&screen_id=edit-comments&has_focus=false",
    method: "POST",
    mode: "cors",
    credentials: "omit",
  }
)
  .then((response) => response.json())
  .then((data) => console.log(data.text()))
  .catch((error) => console.log(error));

@key88sf
Copy link
Author

key88sf commented May 16, 2024

The code you provided doesn't work for me because I don't have the alax_check_image endpoint. Would you be able to provide instructions on how to recreate this in Playground? I would love to help, but first I need to be able to recreate the issue.

This isn't an endpoint, it's just a part of the JSON data being sent -- so not really important. We just use that to ensure the request is coming from Wordpress.

Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?

@bgrgicak
Copy link
Collaborator

Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?

Yes, you can use the device storage option inside Playground.
Alternatively, you could use WP-NOW as a development environment. WP-NOW is slightly different from the web version, so in case your code works with WP-NOW, this would be a Playground web issue.

@adamziel
Copy link
Collaborator

Is there any way to test changes to the plugin code in playground without actually committing new code to SVN?

Or you could:

  • ZIP your plugin and use the Plugins tab in wp-admin to upload it
  • import it from GitHub if your workflow involves pull requests

It would be handy to document different workflow options for plugin preview development. Let's link this issue with #772 for the upcoming doc overhaul

@key88sf
Copy link
Author

key88sf commented May 16, 2024

@bgrgicak I figured out what is causing the problem. It is the async: false setting in the jQuery.ajax() call.

If I set this to true, the POST to admin-ajax.php works fine (200 response). Setting to false results in a 404 Not Found error. I'm not sure why using synchronous results in a 404 though?

The jQuery docs (https://api.jquery.com/Jquery.ajax/) only say that if you make a synchronous request via cross-domain, it is not supported -- but the call works fine on "real" WP instances, just not in the Playground.

Any ideas?

@bgrgicak
Copy link
Collaborator

If I set this to true, the POST to admin-ajax.php works fine (200 response). Setting to false results in a 404 Not Found error. I'm not sure why using synchronous results in a 404 though?

Great find, I can confirm that async false triggers a 404.

Here is an example that returns a 404, but it returns 200 if async is true.

jQuery = import('https://code.jquery.com/jquery-3.7.1.min.js');

jQuery.ajax({
    url: wp.src.match(/(^[^\/]*\/\/[^\/]*\/[^\/]*)\/.*/)[1] + "/wp-admin/admin-ajax.php",
    type: 'post',
    headers: { "Accept-Encoding" : "gzip" },
    dataType: 'json',
    async: false,
    data: {
        action: 'heartbeat',
    },
}).done(function(data) {
	console.log(data);
});

@bgrgicak
Copy link
Collaborator

From looking at the ajax documentation this part stands out Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active..
I assume that when a sync request is sent, Playground is blocked from running and accepting the request.

@adamziel please correct me if I'm wrong.

@key88sf I would suggest that you to rewrite the code to be async. I'm not sure if Playground would be able to support sync requests, and in general they are a bad practice because they block the browser while running.

@key88sf
Copy link
Author

key88sf commented May 17, 2024

@bgrgicak Cool we can try to rewrite as an async call. I'm sure there are other plugins out there which make sync requests so if possible to support this, that would be great!

@adamziel
Copy link
Collaborator

adamziel commented May 17, 2024

I assume that when a sync request is sent, Playground is blocked from running and accepting the request.

PHP runs in a worker, the only relevant part that would get blocked part is this event listener relaying messages between the service worker and PHP web worker:

navigator.serviceWorker.addEventListener(

The service worker used to talk directly to the web worker via a BroadcastChannel, but it wasn't working consistently across web browser and there were also issues with CORS/embedding Playground:

* This used to be implemented with a BroadcastChannel, but
* it didn't work in Safari. BroadcastChannel breaks iframe
* embedding the playground in Safari.

If this, or any other communication technique would work consistently these days, we could refactor that part.

Relevant article: https://web.dev/articles/two-way-communication-guide

@adamziel adamziel changed the title admin-ajax.php gives 404 error Synchronous XHR request not supported, yield a 404 error May 17, 2024
@adamziel adamziel changed the title Synchronous XHR request not supported, yield a 404 error Synchronous XHR request not supported, always yielding a 404 error May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Triage [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests

3 participants