web-dev-qa-db-fra.com

Erreur HTTP générique/inconnue avec le code de réponse utilisant UnityWebRequest

J'essayais d'utiliser les fonctions API de certains serveurs et je suis soudainement tombé sur cette erreur. Je vais l'expliquer après l'exemple de code:

public IEnumerator Post(Dictionary<string, string> data)
    {
        var request = UnityWebRequest.Post(Url, data);
        request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");

        yield return request.Send();

        if (request.isError)
           UpdateNetworkLog("Network error has occured: " + request.error);
        else
            // Some code after success
    }

Comme vous pouvez le constater, je l’ai surtout tiré du manuel de Unity en considérant POST request here . Mais, il y a un problème - la demande n'a jamais abouti correctement, il y a toujours une erreur (qui est affichée à l'aide de la fonction UpdateNetworkLog): "Erreur HTTP générique/inconnue", alors que le code de réponse de la demande est 0. En outre, j'ai essayé d'utiliser l'ancienne méthode méthode de ce manuel et la classe WWW obtenant le même résultat.

Je pense que le problème réside dans la façon dont Unity obtient la réponse: j'ai vérifié les paquets via Wireshark, ma demande POST et la réponse du serveur sont parfaitement correctes, sans erreur ni erreur.

Un autre problème important est que j'utilise WebGL, et tout va bien dans Editor, le programme obtient la réponse appropriée et fonctionne correctement. L'erreur apparaît uniquement après que j'ai créé et exécuté le jeu dans le navigateur (testé sous Chrome et Safari). Aussi, essayé de le lancer en utilisant pas le lecteur Unity WebGL, mais XAMPP: le même.

Merci pour toutes les réponses futures, car Google n'en sait rien.

3
KotovP

Solution potentielle 1

Depuis la documentation Unity sur l'utilisation de UnityWebRequest avec WebGL:

Les classes WWW et UnityWebRequest sont prises en charge dans WebGL. Ils sont implémentés à l'aide de la classe XMLHttpRequest en JavaScript, le navigateur permettant de gérer les demandes WWW. Cela impose certaines restrictions de sécurité pour l'accès aux ressources interdomaines. Fondamentalement, toute demande WWW adressée à un serveur différent du serveur hébergeant le contenu WebGL doit être autorisée par le serveur auquel vous tentez d'accéder. Pour accéder aux ressources WWW interdomaines dans WebGL, le serveur auquel vous essayez d'accéder doit autoriser cette opération à l'aide de CORS.

Ma meilleure hypothèse est que le serveur CORS auquel vous essayez d'accéder n'a pas été correctement configuré ou configuré. Lorsque votre code est exécuté dans un navigateur, le navigateur lui-même gère la demande et soumet par conséquent votre code aux restrictions de sécurité de ce navigateur. Votre programme et le serveur ne sont pas sur le même domaine et le navigateur n'aime pas cela.

Si tel est votre problème, alors sans plus d'informations, il m'est difficile de proposer une solution. Votre article semble indiquer que vous êtes peut-être relativement nouveau en codage (ou du moins en codage lié à HTTP), et que les meilleures solutions que je puisse trouver à votre problème impliquent des méthodes relativement complexes, telles que en utilisant JavaScript à la place de UnityWebRequest.

Solution potentielle 2

Bien entendu, le problème réel pourrait même résulter de votre code environnant ou du serveur auquel vous essayez d'accéder. Quel est votre code pour la fonction qui appelle Post()? Il pourrait y avoir un problème avec l'ordre des événements qui apparaît uniquement lorsque le code est exécuté dans un navigateur (où JavaScript gère la demande POST).

En passant, si le serveur auquel vous essayez d'accéder dispose d'une documentation pour leur API, votre problème peut être traité quelque part.

4
Allison Meek

La première chose à souligner est que UnityWebRequest renvoie la réponse dans 

request.downloadHandler.text

En ne renvoyant que les informations d'erreur générales dans 

request.error


Maintenant, si votre cas est comme le mien et que vous avez mis à niveau Unity uniquement pour que tout votre code de réseau soit cassé, l'erreur que vous verrez probablement est liée à Content-Length  

En effet, pour les classes WWW et UnityWebRequest, le paramètre chunkedTransfer est activé par défaut . Cela semble gâcher la façon dont la longueur du contenu est envoyée et provoque l'erreur.

Bien que chunkedTransfer puisse actuellement être désactivé pour UnityWebRequest, il ne peut pas être désactivé pour la classe WWW au moment de l'écriture. Pour moi, cela signifiait réécrire tout mon ancien code réseau pour utiliser plutôt UnityWebRequest et définir 

myUnityWebRequest.chunkedTransfer = false;

Remarque: UnityWebRequest ne prend actuellement pas en charge les POST sans données. Vous devez toujours utiliser la classe WWW pour cela.

5
Maxx

Ce problème est très commun. Si vous avez travaillé avec Rest API, les choses sont assez faciles à comprendre.

Activer CORS:

J'ai créé une API de repos utilisant un flacon en python et elle était hébergée sur Heroku. L’avantage de Heroku était qu’il supportait CORS par défaut et qu’il n’était pas nécessaire de le configurer. De nos jours, le serveur maximal sur lequel vous hébergez votre application, en particulier python, a la même installation. Donc, ceux qui ont un problème lié à la CORS doivent d'abord activer CROS, c'est obligatoire.

Test dans Postman:

Il est nécessaire de tester votre API dans Postman. Si votre application ne prend toujours pas en charge le système CORS, cela fonctionnera dans Postman. Donc, travailler dans postier ne garantit pas que cela fonctionnera dans Unity. La prochaine chose importante à considérer est les en-têtes que vous utilisez dans le postier.

Comme: {"Clé": "Type de contenu", "valeur": "application/json" }

parce que vous devez également le transmettre dans l’entête www de l’unité.

La prochaine chose à observer est ce que vous passez dans le corps et comment vous le transmettez. Normalement, nous l’envoyons sous forme de JSON (application/json) dans Postman.

Comme:

`{
    "username":"Mukesh",
    "password":"admin@1234",
    "email_id":"[email protected]",
    "us_dollar":"2000000000",
    "device_id":"123456789"

}`

Désormais, si votre API compatible CORS fonctionne correctement dans Postman, détendez-vous, cela fonctionnera également dans l’unité.

Partie Unité: 

Je dois d'abord créer une classe qui convertira en Json.

[Serializable]
public class UserRegistration
{
    //CAUTION:
    //NOTE:
    //DO NOT ALTER THE NAME OF PARAMETERS .
    //THE JSON key WILL FAIL THEN .Properties will be the key of JSON .
    /// <summary>
    /// User name .
    /// </summary>
    public  string username;
    /// <summary>
    /// Password .
    /// </summary>
    public string password;
    /// <summary>
    /// Emil id.
    /// </summary>
    public string email_id;
    /// <summary>
    /// JoeGames Doller .
    /// </summary>
    public string us_dollar;
    /// <summary>
    /// Device id .
    /// </summary>
    public  string device_id;

    /// <summary>
    /// Constructor .
    /// </summary>
    /// <param name="username"></param>
    /// <param name="password"></param>
    /// <param name="email_id"></param>
    /// <param name="us_dollar"></param>
    /// <param name="device_id"></param>
    public UserRegistration(string username, string password, string email_id, string us_dollar, string device_id)
    {
        this.username = username;
        this.password = password;
        this.email_id = email_id;
        this.us_dollar = us_dollar;
        this.device_id = device_id;
    }

}

La prochaine chose que vous devez convertir l'objet en json.

//var create json.
    var userregistration = new UserRegistration(
        username: username,
        password: password,
        email_id: emailid,
        us_dollar: joeGamesDollar.ToString(),
        device_id: deviceid);
    //convert to json.
    var json = JsonUtility.ToJson(userregistration);
    //debug.
    Debug.Log("Print json"+json);
    //update json.
    json = json.Replace("'", "\"");

Ensuite, convertissez json en octet et créez le post avec l’en-tête.

//Encode the JSON string into a bytes
    var postData = System.Text.Encoding.UTF8.GetBytes(json);
    //create headers.
    //Add keys an values .
    var headers = new Dictionary<string, string> {{"Content-Type", "application/json"}};
    //Now call a new WWW request
    var www = new WWW(url,postData,headers);
    //Yield return www .
    yield return www;

    Debug.Log("Error" + www.error.ToString());
    Debug.Log("Data" + www.text);
    Debug.Log(www.responseHeaders+"Done"+www.isDone);
    //dispose.
    www.Dispose();

N'oubliez pas de l'écrire dans un énumérateur. Si vous utilisez quelque chose 

comme:

IEnumerator Upload()
    {
        WWWForm form = new WWWForm();
        form.AddField("username", "Mukesh");
        form.AddField("password", "admin@1234");
        form.AddField("email_id", "[email protected]");
        form.AddField("us_dollar", "2000000");
        form.AddField("device_id", device_id);


        using (UnityWebRequest www = UnityWebRequest.Post(url, form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
            }
            else
            {
                Debug.Log("Form upload complete!");
            }
        }
    } 

Vous obtiendrez une erreur générique/inconnue car Unity Web Request ne pourra pas publier ni envoyer les données car votre API est requise dans ce cas.

NOTE: Quelque temps 400 Requête incorrecte est également utilisée comme erreur HTTP inconnue générique/inconnue dans l'unité. N'oubliez donc pas de vérifier le code dans le backend pour vous assurer que votre API ne reçoit aucune exception.

1
Reezoo Bose