web-dev-qa-db-fra.com

Le script d'application envoie une réponse 405 lors de la tentative d'envoi d'une demande POST

J'ai publié un script d'application publiquement (n'importe qui, même anonyme) avec une méthode doPost comme suit,

 function doPost(e){
    var sheet = SpreadsheetApp.getActiveSheet();
    var length = e.contentLength;
    var body = e.postData.contents;
    var jsonString = e.postData.getDataAsString();
    var jsonData = JSON.parse(jsonString);
    sheet.appendRow([jsonData.title, length]);
    var MyResponse = "works";
    return ContentService.createTextOutput(MyResponse).setMimeType(ContentService.MimeType.JAVASCRIPT);
}

Lorsque j'ai envoyé une demande de publication avec un objet JSON avec Advanced Rest Client, tout fonctionne et renvoie une réponse 200 OK. Mais lorsque j'essaie d'envoyer une demande de publication avec les axios de réaction à partir d'une application de réaction hébergée localement, elle envoie une réponse 405.

XMLHttpRequest cannot load https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec. Response for preflight has invalid HTTP status code 405

J'ai également activé le partage de ressources Cross Origin dans le navigateur. La fonction qui envoie la demande POST est la suivante,

axios({
          method:'post',
          url:'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
          data: {
            "title": 'Fred',
            "lastName": 'Flintstone'
          }
        }).then(function (response) {
            console.log(response);
          })
          .catch(function (error) {
            console.log(error);
          });

Si quelqu'un peut me montrer pourquoi je reçois une réponse 405, ce serait reconnaissant.

10
Achala Dissanayake

Vous avez raté la partie importante:

La réponse pour le contrôle en amont a un code d'état HTTP non valide 405.

Votre navigateur effectue une demande de contrôle en amont , qui utilise la méthode HTTP OPTIONS . Il s'agit de vérifier si le serveur autorisera la demande POST - la 405 le code d'état est envoyé dans la réponse à la demande OPTIONS, et non à votre demande POST.

Une demande de contrôle en amont CORS est une demande CORS qui vérifie si le protocole CORS est compris. La source


De plus, pour les méthodes de requête HTTP qui peuvent provoquer des effets secondaires sur les données du serveur (en particulier, pour les méthodes HTTP autres que GET , ou pour POST utilisation avec certains types MIME ), la spécification oblige les navigateurs à "contrôler" la demande, en sollicitant les méthodes prises en charge auprès du serveur avec un HTTP OPTIONS méthode de demande, puis, sur "approbation" du serveur, envoi de la demande réelle avec la méthode de demande HTTP réelle. La source
Certaines demandes ne déclenchent pas CORS preflight . Celles-ci sont appelées "demandes simples" dans cet article [...] La source
Cette section de l'article détaille les conditions qu'une demande doit remplir pour être considérée comme une "simple demande".
[...] les requêtes "en amont" envoient d'abord une requête HTTP par la méthode OPTIONS à la ressource de l'autre domaine, afin de déterminer si le réel la demande est sûre à envoyer. Les demandes intersites sont contrôlées en amont comme ceci car elles peuvent avoir des implications sur les données des utilisateurs. La source
Cette section de l'article détaille les conditions qui entraînent le contrôle en amont d'une demande.

Dans ce cas, les éléments suivants entraînent le contrôle en amont de la demande:

[...] si le Content-Type l'en-tête a une valeur autre que la suivante:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

La valeur de Content-Type l'en-tête est défini sur application/json;charset=utf-8 par axios. En utilisant text/plain;charset=utf-8 ou text/plain résout le problème:

axios({
    method: 'post',
    url: 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
    data: {
        title: 'Fred',
        lastName: 'Flintstone',
    },
    headers: {
        'Content-Type': 'text/plain;charset=utf-8',
    },
}).then(function (response) {
    console.log(response);
}).catch(function (error) {
    console.log(error);
});
13
Spooky

Une autre façon pour quelqu'un qui aura ce problème à l'avenir:

(dans mon cas, en utilisant 'Content-Type': 'text/plain;charset=utf-8' ne fonctionne pas)

Selon ce document https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format

À la place d'utiliser text/plain;charset=utf-8 comme réponse acceptée, vous pouvez utiliser application/x-www-form-urlencoded:

const axios = require('axios')
const qs = require('qs')

const url = 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec'

const data = {
        "title": 'Fred',
        "lastName": 'Flintstone'
}

const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url
}

axios(options)
  .then(function(response) {
    console.log(response.data)
  })
  .catch(function(error) {
    console.log(error)
  })
1
Hoang Trinh

Je pense que vous devez renvoyer des données JSON. Il est possible que vous deviez retourner JSONP à une demande d'un navigateur, mais voici ce que je pense que vous devez faire:

return ContentService.createTextOutput(JSON.stringify({message: MyResponse})).setMimeType(ContentService.MimeType.JSON);

Si cela ne fonctionne pas, c'est probablement que vous devez retourner JSONP pour qu'il s'exécute dans le navigateur. Voici quelques documents pour vous aider: https://developers.google.com/apps-script/guides/content#serving_jsonp_in_web_pages

1
Jordan Rhea