web-dev-qa-db-fra.com

Lecture des en-têtes HTTP dans un contrôleur Spring REST)

J'essaie de lire les en-têtes HTTP dans Spring REST. J'ai suivi this . Mais j'obtiens cette erreur:

Aucun lecteur de corps de message n'a été trouvé pour la classe Java.lang.String,
ContentType: application/octet-stream

Je suis nouveau sur Java et Spring, donc je ne peux pas comprendre cela.

Voici à quoi ressemble mon appel:

@WebService(serviceName = "common")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public interface CommonApiService {

    @GET
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/data")
    public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @DefaultValue ("") @QueryParam("ID") String id);
}

J'ai essayé @Context: HTTPHeader est null dans ce cas.

Comment obtenir les valeurs des en-têtes HTTP?

29
Ashwani K

L'erreur que vous obtenez ne semble pas être liée à RequestHeader.

Et vous semblez confondre Spring REST services with JAX-RS , la signature de votre méthode devrait ressembler à ceci:

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data")
@ResponseBody
public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @RequestParam(value = "ID", defaultValue = "") String id) {
    // your code goes here
}

Et votre classe REST devrait avoir des annotations telles que:

@Controller
@RequestMapping("/rest/")


En ce qui concerne la question, un autre moyen d’obtenir les en-têtes HTTP consiste à insérer le HttpServletRequest dans votre méthode et ensuite obtenir l'en-tête souhaité à partir de là.

Exemple:

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data")
@ResponseBody
public ResponseEntity<Data> getData(HttpServletRequest request, @RequestParam(value = "ID", defaultValue = "") String id) {
    String userAgent = request.getHeader("user-agent");
}

Ne vous inquiétez pas pour l'injection de HttpServletRequest car Spring fait cette magie pour vous;)

64
Mário Fernandes

Je vais vous donner un exemple de la façon dont j'ai lu les en-têtes REST de mes contrôleurs. Mes contrôleurs acceptent uniquement application/json comme type de requête si j'ai des données à lire. I soupçonnez que votre problème est que vous avez une application/octet-stream que Spring ne sait pas gérer.

Normalement, mes contrôleurs ressemblent à ceci:

@Controller
public class FooController {
    @Autowired
    private DataService dataService;

    @RequestMapping(value="/foo/", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<Data> getData(@RequestHeader String dataId){
        return ResponseEntity.newInstance(dataService.getData(dataId);
    }

Maintenant, il y a beaucoup de code qui fait des choses en arrière-plan ici, donc je vais le décomposer pour vous.

ResponseEntity est un objet personnalisé renvoyé par chaque contrôleur. Il contient une fabrique statique permettant la création de nouvelles instances. Mon service de données est une classe de service standard.

La magie opère dans les coulisses, car vous utilisez JSON, vous devez dire à Spring d’utiliser Jackson pour mapper les objets HttpRequest afin qu’il sache à quoi vous avez affaire.

Vous faites cela en spécifiant ceci dans votre <mvc:annotation-driven> bloc de votre config

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

ObjectMapper est simplement une extension de com.fasterxml.jackson.databind.ObjectMapper et c'est ce que Jackson utilise pour mapper votre demande de JSON dans un objet.

Je suppose que vous obtenez votre exception parce que vous n'avez pas spécifié de mappeur capable de lire un Octet-Stream dans un objet, ou quelque chose que Spring puisse gérer. Si vous essayez de télécharger un fichier, c'est tout autre chose.

Donc, ma demande qui est envoyée à mon contrôleur ressemble à quelque chose comme ceci a simplement un en-tête supplémentaire appelé dataId.

Si vous voulez changer cela en paramètre de requête et utiliser @RequestParam String dataId pour lire l'ID de la requête, votre requête ressemblerait à ceci:

contactId : {"fooId"} 

Ce paramètre de requête peut être aussi complexe que vous le souhaitez. Vous pouvez sérialiser un objet entier en JSON, l'envoyer en tant que paramètre de requête et Spring le sérialisera (à l'aide de Jackson) dans un objet Java prêt à être utilisé).

Exemple dans le contrôleur:

@RequestMapping(value = "/penguin Details/", method = RequestMethod.GET)
@ResponseBody
public DataProcessingResponseDTO<Pengin> getPenguinDetailsFromList(
        @RequestParam DataProcessingRequestDTO jsonPenguinRequestDTO)

Demande envoyée:

jsonPengiunRequestDTO: {
    "draw": 1,
    "columns": [
        {
            "data": {
                "_": "toAddress",
                "header": "toAddress"
            },
            "name": "toAddress",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "fromAddress",
                "header": "fromAddress"
            },
            "name": "fromAddress",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "customerCampaignId",
                "header": "customerCampaignId"
            },
            "name": "customerCampaignId",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "penguinId",
                "header": "penguinId"
            },
            "name": "penguinId",
            "searchable": false,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "validpenguin",
                "header": "validpenguin"
            },
            "name": "validpenguin",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "",
                "header": ""
            },
            "name": "",
            "searchable": false,
            "orderable": false,
            "search": {
                "value": "",
                "regex": false
            }
        }
    ],
    "order": [
        {
            "column": 0,
            "dir": "asc"
        }
    ],
    "start": 0,
    "length": 10,
    "search": {
        "value": "",
        "regex": false
    },
    "objectId": "30"
}

qui est automatiquement rediffusé dans un objet DataProcessingRequestDTO avant d’être donné au contrôleur prêt à être utilisé.

Comme vous pouvez le constater, cette solution est assez puissante pour vous permettre de sérialiser vos données depuis JSON vers un objet sans avoir à écrire une seule ligne de code. Vous pouvez le faire pour @RequestParam et @RequestBody qui vous permet d’accéder au JSON dans vos paramètres ou dans le corps de votre requête, respectivement.

Maintenant que vous avez un exemple concret à suivre, vous ne devriez plus rencontrer de problèmes une fois que vous avez modifié votre type de demande en application/json.

7
JamesENL