Je travaille sur un service Web RESTful en Java. J'ai besoin d'un bon moyen d'envoyer des messages d'erreur au client si quelque chose ne va pas.
Selon le Javadoc , HttpServletResponse.setStatus(int status, String message)
est obsolète "en raison de la signification ambiguë du paramètre de message."
Existe-t-il un moyen préféré de définir le message d'état ou " phrase de raison " de la réponse? La méthode sendError(int, String)
ne le fait pas.
EDIT: pour clarifier, je souhaite modifier la ligne d'état HTTP, c'est-à-dire "HTTP/1.1 404 Not Found"
, pas le contenu du corps. Plus précisément, j'aimerais envoyer des réponses comme "HTTP/1.1 400 Missing customerNumber parameter"
.
Je ne pense pas qu'un client RESTful s'attendrait à regarder la phrase de raison pour comprendre ce qui a mal tourné; la plupart des services RESTful que j'ai vus/utilisés enverront les informations d'état standard et un message étendu dans le corps de la réponse. sendError(int, String)
est idéal pour cette situation.
Si vous utilisez Tomcat, consultez le paramètre org.Apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER:
http://Tomcat.Apache.org/Tomcat-5.5-doc/config/systemprops.html
Voir cette page pour quelques détails sur la vulnérabilité d'origine:
http://www.securityfocus.com/archive/1/archive/1/495021/100/0/threaded
Après votre clarification, j'ai essayé ceci dans Tomcat. Exécution
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "message goes here");
retour
HTTP/1.1 400 message goes here
comme première ligne de la réponse.
Il doit y avoir un problème avec le conteneur de servlet que vous utilisez.
Je ne connais pas très bien les "meilleures pratiques" autour de REST. Mais je sais que le concept est basé sur HTTP et comment il est censé fonctionner naturellement. Alors, que diriez-vous d'utiliser un type MIME et un texte simple à l'intérieur du corps pour une erreur d'application, comme "application/myapp-exception" et certains "Bla bla"? Vous pouvez fournir une bibliothèque client pour cela.
Je n'utiliserais pas de codes de réponse HTTP pour les erreurs d'application. Parce que j'aime savoir ce qui échoue: que ce soit mon application ou mon serveur HTTP.
(J'espère que je verrai ici aussi quelques conseils sur les meilleures pratiques.)
Dans l'application Web propulsée par Spring, fonctionnant sur Tomcat, j'utilise le bean suivant:
import Java.util.Map;
import Java.util.Set;
import Java.util.Map.Entry;
import org.springframework.beans.factory.InitializingBean;
public class SystemPropertiesInitializingBean implements InitializingBean {
private Map<String, String> systemProperties;
@Override
public void afterPropertiesSet() throws Exception {
if (null == systemProperties || systemProperties.isEmpty()) {
return;
}
final Set<Entry<String, String>> entrySet = systemProperties.entrySet();
for (final Entry<String, String> entry : entrySet) {
final String key = entry.getKey();
final String value = entry.getValue();
System.setProperty(key, value);
}
}
public void setSystemProperties(final Map<String, String> systemProperties) {
this.systemProperties = systemProperties;
}
}
Et dans applicationContext.xml:
<bean class="....SystemPropertiesInitializingBean">
<property name="systemProperties">
<map>
<entry key="org.Apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER" value="true"/>
</map>
</property>
</bean>
Ce que vous essayez d'accomplir n'est pas vraiment clair. Ma première pensée a été le sendError mais vous dites que cela ne fait pas ce que vous voulez ... contient le message d'erreur ou le code et toute autre information utile?
J'ai fait quelque chose comme ça pour les services RESTful basés sur Spring-mvc il y a quelque temps et cela a bien fonctionné, mais vous devez à peu près intercepter et gérer chaque exception pour empêcher le client d'obtenir un message générique 500 ou quelque chose. Les résolveurs des exceptions de printemps ont bien fonctionné pour cela.
J'espère que cela vous aidera ... sinon, peut-être un peu plus de clarté sur ce que vous essayez d'accomplir. Désolé si je suis dense et que je manque quelque chose d'évident.
Je pense que le sendError
devrait le faire, mais votre serveur d'applications peut échouer ... IBM WebSphere 3.5 a échoué il y a longtemps alors que Tomcat propagerait très bien le message; voir JavaServer Pages (JSP) et JSTL - Page d'erreur: conserver l'en-tête "HTTP/1.x 400 My message"? sur les forums Sun.
Finalement, j'ai utilisé la solution de contournement suivante, mais c'est une sorte de JSP spécifique, et peut en fait être ancien:
<%@ page isErrorPage="true" %>
<%
// This attribute is NOT set when calling HttpResponse#setStatus and then
// explicitely incuding this error page using RequestDispatcher#include()
// So: only set by HttpResponse#sendError()
Integer origStatus =
(Integer)request.getAttribute("javax.servlet.error.status_code");
if(origStatus != null) {
String origMessage =
(String)request.getAttribute("javax.servlet.error.message");
if(origMessage != null) {
response.reset();
response.setContentType("text/html");
// deprecated, but works:
response.setStatus(origStatus.intValue(), origMessage);
// would yield recursive error:
// response.sendError(origStatus, origMessage);
}
}
%>
Et s'il vous arrive de tester avec Internet Explorer: désactivez "Afficher les messages d'erreur HTTP conviviaux". (Lorsqu'il ne le désactive pas, IE a une exigence étrange d'une longueur minimale du contenu HTML qui, s'il n'est pas satisfait, ferait - ou fera - IE afficher son propre message d'erreur à la place. Voir aussi la clé de registre HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\ErrorThresholds
chez Microsoft Description des messages d'erreur du protocole de transport hypertexte .)