在 Spring REST 控制器中读取 HTTP headers
Reading HTTP headers in a Spring REST controller
我正在尝试在基于 Spring 的 REST API 中读取 HTTP headers。我关注了this。但我收到此错误:
No message body reader has been found for class java.lang.String,
ContentType: application/octet-stream
我是 Java 和 Spring 的新手,所以搞不懂。
我的电话是这样的:
@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);
}
我试过@Context
:在这种情况下,HTTPHeader 是null
。
如何从 HTTP headers 获取值?
您收到的错误似乎与 RequestHeader 无关。
而且您似乎将 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
}
你的 REST class 应该有这样的注释:
@Controller
@RequestMapping("/rest/")
关于实际问题,另一种获取 HTTP headers 的方法是将 HttpServletRequest 插入您的方法,然后从那里获取所需的 header。
示例:
@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");
}
不用担心 HttpServletRequest 的注入,因为 Spring 会为您带来魔法 ;)
我将举例说明我如何为我的控制器读取 REST headers。如果我有需要读取的数据,我的控制器只接受 application/json 作为请求类型。我怀疑您的问题是您有一个 Spring 不知道如何处理的 application/octet-stream。
通常我的控制器是这样的:
@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);
}
现在这里有很多代码在后台执行操作,所以我将为您分解。
ResponseEntity 是每个控制器 returns 的自定义 object。它包含一个允许创建新实例的静态工厂。我的数据服务是标准服务 class.
魔术发生在幕后,因为您正在使用 JSON,您需要告诉 Spring 使用 Jackson 映射 HttpRequest objects 以便它知道您的内容正在处理。
您可以通过在配置的 <mvc:annotation-driven>
块中指定它来做到这一点
<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 只是 com.fasterxml.jackson.databind.ObjectMapper
的扩展,Jackson 使用它来实际将您的请求从 JSON 映射到 object.
我怀疑您遇到了异常,因为您没有指定可以将 Octet-Stream 读入 object 或 Spring 可以处理的映射器。如果您正在尝试上传文件,那完全是另一回事。
所以我发送到我的控制器的请求看起来像这样只是有一个额外的 header 称为 dataId
。
如果您想将其更改为请求参数并使用 @RequestParam String dataId
从请求中读取 ID,您的请求将类似于:
contactId : {"fooId"}
这个请求参数可以很复杂,只要你喜欢。您可以将整个 object 序列化为 JSON,将其作为请求参数发送,然后 Spring 将其(使用 Jackson)序列化回 Java Object 就绪供您使用。
控制器中的示例:
@RequestMapping(value = "/penguin Details/", method = RequestMethod.GET)
@ResponseBody
public DataProcessingResponseDTO<Pengin> getPenguinDetailsFromList(
@RequestParam DataProcessingRequestDTO jsonPenguinRequestDTO)
已发送请求:
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"
}
在提供给控制器供我使用之前,它会自动序列化回 DataProcessingRequestDTO object。
如您所见,这非常强大,允许您将数据从 JSON 序列化为 object,而无需编写一行代码。您可以为 @RequestParam
和 @RequestBody
执行此操作,这允许您在参数中访问 JSON 或分别请求 body。
现在您有了一个具体的示例,一旦您将请求类型更改为 application/json
。
,您应该不会有任何问题
不是在每个方法中都使用 HttpServletRequest
对象,而是通过构造函数自动装配来保留在控制器的上下文中。然后你可以从控制器的所有方法访问。
public class OAuth2ClientController {
@Autowired
private OAuth2ClientService oAuth2ClientService;
private HttpServletRequest request;
@Autowired
public OAuth2ClientController(HttpServletRequest request) {
this.request = request;
}
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<String> createClient(@RequestBody OAuth2Client client) {
System.out.println(request.getRequestURI());
System.out.println(request.getHeader("Content-Type"));
return ResponseEntity.ok();
}
}
我正在尝试在基于 Spring 的 REST API 中读取 HTTP headers。我关注了this。但我收到此错误:
No message body reader has been found for class java.lang.String,
ContentType: application/octet-stream
我是 Java 和 Spring 的新手,所以搞不懂。
我的电话是这样的:
@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);
}
我试过@Context
:在这种情况下,HTTPHeader 是null
。
如何从 HTTP headers 获取值?
您收到的错误似乎与 RequestHeader 无关。
而且您似乎将 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
}
你的 REST class 应该有这样的注释:
@Controller
@RequestMapping("/rest/")
关于实际问题,另一种获取 HTTP headers 的方法是将 HttpServletRequest 插入您的方法,然后从那里获取所需的 header。
示例:
@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");
}
不用担心 HttpServletRequest 的注入,因为 Spring 会为您带来魔法 ;)
我将举例说明我如何为我的控制器读取 REST headers。如果我有需要读取的数据,我的控制器只接受 application/json 作为请求类型。我怀疑您的问题是您有一个 Spring 不知道如何处理的 application/octet-stream。
通常我的控制器是这样的:
@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);
}
现在这里有很多代码在后台执行操作,所以我将为您分解。
ResponseEntity 是每个控制器 returns 的自定义 object。它包含一个允许创建新实例的静态工厂。我的数据服务是标准服务 class.
魔术发生在幕后,因为您正在使用 JSON,您需要告诉 Spring 使用 Jackson 映射 HttpRequest objects 以便它知道您的内容正在处理。
您可以通过在配置的 <mvc:annotation-driven>
块中指定它来做到这一点
<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 只是 com.fasterxml.jackson.databind.ObjectMapper
的扩展,Jackson 使用它来实际将您的请求从 JSON 映射到 object.
我怀疑您遇到了异常,因为您没有指定可以将 Octet-Stream 读入 object 或 Spring 可以处理的映射器。如果您正在尝试上传文件,那完全是另一回事。
所以我发送到我的控制器的请求看起来像这样只是有一个额外的 header 称为 dataId
。
如果您想将其更改为请求参数并使用 @RequestParam String dataId
从请求中读取 ID,您的请求将类似于:
contactId : {"fooId"}
这个请求参数可以很复杂,只要你喜欢。您可以将整个 object 序列化为 JSON,将其作为请求参数发送,然后 Spring 将其(使用 Jackson)序列化回 Java Object 就绪供您使用。
控制器中的示例:
@RequestMapping(value = "/penguin Details/", method = RequestMethod.GET)
@ResponseBody
public DataProcessingResponseDTO<Pengin> getPenguinDetailsFromList(
@RequestParam DataProcessingRequestDTO jsonPenguinRequestDTO)
已发送请求:
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"
}
在提供给控制器供我使用之前,它会自动序列化回 DataProcessingRequestDTO object。
如您所见,这非常强大,允许您将数据从 JSON 序列化为 object,而无需编写一行代码。您可以为 @RequestParam
和 @RequestBody
执行此操作,这允许您在参数中访问 JSON 或分别请求 body。
现在您有了一个具体的示例,一旦您将请求类型更改为 application/json
。
不是在每个方法中都使用 HttpServletRequest
对象,而是通过构造函数自动装配来保留在控制器的上下文中。然后你可以从控制器的所有方法访问。
public class OAuth2ClientController {
@Autowired
private OAuth2ClientService oAuth2ClientService;
private HttpServletRequest request;
@Autowired
public OAuth2ClientController(HttpServletRequest request) {
this.request = request;
}
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<String> createClient(@RequestBody OAuth2Client client) {
System.out.println(request.getRequestURI());
System.out.println(request.getHeader("Content-Type"));
return ResponseEntity.ok();
}
}