75 votes

Une grande demande de service web WCF échoue avec (400) HTTP Bad Request.

J'ai rencontré ce problème apparemment commun et je n'ai pas réussi à le résoudre.

Si j'appelle mon service web WCF avec un nombre relativement faible d'éléments dans un paramètre de tableau (j'ai testé jusqu'à 50), tout va bien.

Cependant, si j'appelle le service web avec 500 éléments, j'obtiens l'erreur Bad Request.

Il est intéressant de noter que j'ai exécuté Wireshark sur le serveur et il apparaît que la demande n'atteint même pas le serveur - l'erreur 400 est générée du côté client.

L'exception est :

System.ServiceModel.ProtocolException : Le serveur distant a renvoyé une réponse inattendue : (400) Bad Request. ---> System.Net.WebException : Le serveur distant a renvoyé une erreur : (400) Bad Request.

Le site system.serviceModel de mon fichier de configuration client :

 <system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IMyService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                allowCookies="false">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    enabled="false" />
                <security mode="None">
                    <transport clientCredentialType="Windows" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="Windows" negotiateServiceCredential="true"
                        establishSecurityContext="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://serviceserver/MyService.svc"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService"
            contract="SmsSendingService.IMyService" name="WSHttpBinding_IMyService" />
    </client>
</system.serviceModel>

Côté serveur, mon fichier web.config contient les éléments suivants system.serviceModel section :

<system.serviceModel>
    <services>
        <service name="MyService.MyService" behaviorConfiguration="MyService.MyServiceBehaviour" >
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyService.MyServiceBinding" contract="MyService.IMyService">
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="MyService.MyServiceBinding">
          <security mode="None"></security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyService.MyServiceBehaviour">
                <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                <serviceMetadata httpGetEnabled="true"/>
                <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

J'ai regardé a assez grand numéro de réponses a cette question con aucun succès .

Quelqu'un peut-il m'aider ?

0 votes

Si le serveur n'est pas atteint, il y a peut-être un problème avec les données envoyées. Peut-être y a-t-il des caractères illégaux dans la requête ? En supposant que c'est SOAP

1 votes

Vous avez donc essayé de définir tous vos attributs "max" (par exemple, maxReceivedMessageSize...) sur un nombre très élevé ?

0 votes

Oui, c'est SOAP. Et il ne devrait pas y avoir de problème avec la requête - comme je l'ai dit, tout fonctionne bien pour un maximum de 50 éléments générés avec la même application...

108voto

Joe Points 60749

Essayez également de définir maxReceivedMessageSize sur le serveur, par exemple à 4 Mo :

<binding name="MyService.MyServiceBinding" maxReceivedMessageSize="4194304">

La principale raison pour laquelle la valeur par défaut (65535 je crois) est si faible est de réduire le risque d'attaques par déni de service (DoS). Vous devez définir une taille supérieure à la taille maximale de la requête sur le serveur et à la taille maximale de la réponse sur le client. Si vous êtes dans un environnement intranet, le risque d'attaques par déni de service est probablement faible, il est donc prudent d'utiliser une valeur beaucoup plus élevée que celle dont vous pensez avoir besoin.

A propos, quelques conseils pour résoudre les problèmes de connexion aux services WCF :

  • Activez le traçage sur le serveur comme décrit dans la section cet article de MSDN .

  • Utilisez un outil de débogage HTTP tel que Fiddler sur le client pour inspecter le trafic HTTP.

1 votes

Incroyable - c'est tout ce que c'était. Merci beaucoup pour votre réponse !

2 votes

Merci pour le lien vers l'outil de traçage !

2 votes

J'ai essayé de faire la même chose de mon côté, mais je n'ai pas pu goûter au succès.

8voto

Mark Davies Points 71

J'ai également rencontré ce problème, mais aucune des solutions ci-dessus n'a fonctionné pour moi, car j'utilisais une liaison personnalisée (pour BinaryXML). Après une longue recherche, j'ai trouvé la réponse ici : Envoi de gros fichiers XML de Silverlight à WCF

Comme j'utilise un customBinding, la maxReceivedMessageSize doit être définie sur l'élément httpTransport sous l'élément binding dans le web.config :

<httpsTransport maxReceivedMessageSize="4194304" />

8voto

user469104 Points 240

Pour ce que cela vaut, une considération supplémentaire lors de l'utilisation de .NET 4.0 est que si un point de terminaison valide n'est pas trouvé dans votre configuration, un point de terminaison par défaut sera automatiquement créé et utilisé.

Le point de terminaison par défaut utilisera toutes les valeurs par défaut. Ainsi, si vous pensez avoir une configuration de service valide avec une grande valeur pour maxReceivedMessageSize, etc., mais qu'il y a un problème avec la configuration, vous obtiendrez quand même le message 400 Bad Request puisqu'un point de terminaison par défaut sera créé et utilisé.

Cette opération se fait de manière silencieuse et est donc difficile à détecter. Vous verrez des messages à cet effet (par exemple "No Endpoint found for Service, creating Default Endpoint" ou similaire) si vous activez le traçage sur le serveur mais il n'y a pas d'autre indication (à ma connaissance).

0 votes

@user469104 : Très bon conseil. Merci. Existe-t-il un moyen de forcer le serveur à utiliser un point de terminaison déclaré manuellement sans écraser le ServiceHost par défaut ?

6voto

RaSor Points 116

Sur le serveur en .NET 4.0, dans le web.config, vous devez également modifier la liaison par défaut. Définissez les 3 paramètres suivants :

<basicHttpBinding>  
    <!-- http://www.intertech.com/Blog/post/NET-40-WCF-Default-Bindings.aspx  
         Enable transfer of large strings with maxBufferSize, maxReceivedMessageSize and maxStringContentLength
    -->  
       <binding **maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"**>  
          <readerQuotas **maxStringContentLength="2147483647"**/>            
       </binding>
</basicHttpBinding>

5voto

Brian Points 82719

Il peut être utile de déboguer le client, de désactiver les Outils \Options\Debugging\General\ Enable Just My Code", cliquez sur Debug. \Exceptions\ catch all first-chance exceptions" pour les exceptions du CLR géré, et voyez s'il y a une exception sous le capot du client avant l'exception de protocole et avant que le message n'atteigne le fil. (Ma supposition serait une sorte d'échec de sérialisation).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X