Java 在 Spring REST 控制器中读取 HTTP 标头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28209242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 05:47:30  来源:igfitidea点击:

Reading HTTP headers in a Spring REST controller

javaspringrestspring-restcontrollerspring-rest

提问by Ashwani K

I am trying to read HTTP headers in Spring based REST API. I followed this. But I am getting this error:

我正在尝试读取基于 Spring 的 REST API 中的 HTTP 标头。我跟着这个。但我收到此错误:

No message body reader has been found for class java.lang.String,
ContentType: application/octet-stream

没有找到类 java.lang.String,
ContentType: application/octet-stream 的消息正文阅读器

I am new to Java and Spring so can't figure this out.

我是 Java 和 Spring 的新手,所以无法弄清楚。

This is how my call looks like:

这是我的电话的样子:

@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);
}

I have tried @Context: HTTPHeader is nullin this case.

我试过@Context: HTTPHeadernull在这种情况下。

How to get values from HTTP headers?

如何从 HTTP 标头中获取值?

采纳答案by Mário Fernandes

The error that you get does not seem to be related to the RequestHeader.

您得到的错误似乎与RequestHeader无关。

And you seem to be confusing Spring REST services with JAX-RS, your method signature should be something like:

而且您似乎将 Spring REST 服务与JAX-RS混淆,您的方法签名应该是这样的:

@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
}

And your REST class should have annotations like:

你的 REST 类应该有这样的注释:

@Controller
@RequestMapping("/rest/")


Regarding the actual question, another way to get HTTP headers is to insert the HttpServletRequestinto your method and then get the desired header from there.


关于实际问题,获取 HTTP 标头的另一种方法是将HttpServletRequest插入到您的方法中,然后从那里获取所需的标头。

Example:

例子:

@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");
}

Don't worry about the injection of the HttpServletRequestbecause Spring does that magic for you ;)

不要担心HttpServletRequest的注入,因为 Spring 为你做了那个魔法;)

回答by JamesENL

I'm going to give you an example of how I read REST headers for my controllers. My controllers only accept application/json as a request type if I have data that needs to be read. I suspect that your problem is that you have an application/octet-stream that Spring doesn't know how to handle.

我将给您一个示例,说明我如何读取控制器的 REST 标头。如果我有需要读取的数据,我的控制器只接受 application/json 作为请求类型。我怀疑您的问题是您有一个 Spring 不知道如何处理的应用程序/八位字节流。

Normally my controllers look like this:

通常我的控制器看起来像这样:

@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);
    }

Now there is a lot of code doing stuff in the background here so I will break it down for you.

现在有很多代码在后台做一些事情,所以我会为你分解。

ResponseEntity is a custom object that every controller returns. It contains a static factory allowing the creation of new instances. My Data Service is a standard service class.

ResponseEntity 是每个控制器返回的自定义对象。它包含一个允许创建新实例的静态工厂。我的数据服务是一个标准的服务类。

The magic happens behind the scenes, because you are working with JSON, you need to tell Spring to use Hymanson to map HttpRequest objects so that it knows what you are dealing with.

神奇发生在幕后,因为您正在使用 JSON,您需要告诉 Spring 使用 Hymanson 来映射 HttpRequest 对象,以便它知道您正在处理什么。

You do this by specifying this inside your <mvc:annotation-driven>block of your config

你可以通过在你<mvc:annotation-driven>的配置块中指定 this 来做到这一点

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

ObjectMapper is simply an extension of com.fasterxml.Hymanson.databind.ObjectMapperand is what Hymanson uses to actually map your request from JSON into an object.

ObjectMapper 只是com.fasterxml.Hymanson.databind.ObjectMapperHyman逊用来将您的请求从 JSON 实际映射到对象的扩展。

I suspect you are getting your exception because you haven't specified a mapper that can read an Octet-Stream into an object, or something that Spring can handle. If you are trying to do a file upload, that is something else entirely.

我怀疑您收到异常是因为您没有指定可以将 Octet-Stream 读入对象的映射器,或者 Spring 可以处理的东西。如果您尝试上传文件,那完全是另一回事。

So my request that gets sent to my controller looks something like this simply has an extra header called dataId.

所以我发送到我的控制器的请求看起来像这样只是有一个名为dataId.

If you wanted to change that to a request parameter and use @RequestParam String dataIdto read the ID out of the request your request would look similar to this:

如果您想将其更改为请求参数并用于@RequestParam String dataId从请求中读取 ID,您的请求将类似于以下内容:

contactId : {"fooId"} 

This request parameter can be as complex as you like. You can serialize an entire object into JSON, send it as a request parameter and Spring will serialize it (using Hymanson) back into a Java Object ready for you to use.

此请求参数可以根据您的喜好复杂化。您可以将整个对象序列化为 JSON,将其作为请求参数发送,Spring 会将其(使用 Hymanson)序列化回 Java 对象,供您使用。

Example In Controller:

控制器中的示例:

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

Request Sent:

请求发送:

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"
}

which gets automatically serialized back into an DataProcessingRequestDTO object before being given to the controller ready for me to use.

在提供给控制器供我使用之前,它会自动序列化回 DataProcessingRequestDTO 对象。

As you can see, this is quite powerful allowing you to serialize your data from JSON to an object without having to write a single line of code. You can do this for @RequestParamand @RequestBodywhich allows you to access JSON inside your parameters or request body respectively.

如您所见,这非常强大,允许您将数据从 JSON 序列化为对象,而无需编写一行代码。您可以为@RequestParam和执行此操作,@RequestBody这允许您分别访问参数或请求正文中的 JSON。

Now that you have a concrete example to go off, you shouldn't have any problems once you change your request type to application/json.

现在您有了一个具体的例子,一旦您将请求类型更改为application/json.