将 JSON 发布到 REST API
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10323957/
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
Posting JSON to REST API
提问by Thomas Buckley
I'm creating a REST API that will accept JSON requests.
我正在创建一个接受 JSON 请求的 REST API。
I'm testing it out using CURL:
我正在使用 CURL 对其进行测试:
curl -i -POST -H 'Accept: application/json' -d '{"id":1,"pan":11111}' http://localhost:8080/PurchaseAPIServer/api/purchase
But getting the following error:
但收到以下错误:
HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 25 Apr 2012 21:36:14 GMT
The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ().
When debugging it never even gets into my create action in the controller.
调试时,它甚至从未进入我在控制器中的创建操作。
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.app.model.Purchase;
import com.app.service.IPurchaseService;
@Controller
public class PurchaseController {
@Autowired
private IPurchaseService purchaseService;
@RequestMapping(value = "purchase", method = RequestMethod.GET)
@ResponseBody
public final List<Purchase> getAll() {
return purchaseService.getAll();
}
@RequestMapping(value = "purchase", method = RequestMethod.POST)
@ResponseStatus( HttpStatus.CREATED )
public void create(@RequestBody final Purchase entity) {
purchaseService.addPurchase(entity);
}
}
UPDATE
更新
I added Hymanson config to AppConfig.java:
我在 AppConfig.java 中添加了 Hymanson 配置:
@Configuration
@ComponentScan(basePackages = "com.app")
public class AppConfig {
@Bean
public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
{
final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
final MappingHymansonHttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymansonHttpMessageConverter();
HttpMessageConverter<?>[] httpMessageConverter = { mappingHymansonHttpMessageConverter };
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return annotationMethodHandlerAdapter;
}
}
My GETs are working correctly now:
我的 GET 现在工作正常:
curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Apr 2012 21:19:55 GMT
[{"id":1,"pan":111}]
But I get the following when attempting a POST:
但是在尝试 POST 时我得到以下信息:
curl -i -X POST -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Thu, 26 Apr 2012 21:29:56 GMT
Connection: close
The request sent by the client was syntactically incorrect ().
My Model:
我的型号:
@Entity
@XmlRootElement
public class Purchase implements Serializable {
/**
*
*/
private static final long serialVersionUID = 6603477834338392140L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long pan;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getPan() {
return pan;
}
public void setPan(Long pan) {
this.pan = pan;
}
}
Any ideas where I'm going wrong?
任何想法我哪里出错了?
Thanks
谢谢
采纳答案by Thomas Buckley
As sdouglasssuggested, Spring MVC automatically detects Hymanson and sets up a MappingHymansonHttpMessageConverter to handle conversion to/from JSON. But I did need explicity configure the converter to get it to work as he also pointed out.
正如sdouglass 所建议的,Spring MVC 会自动检测 Hymanson 并设置一个 MappingHymansonHttpMessageConverter 来处理与 JSON 的转换。但是我确实需要明确配置转换器才能使其正常工作,正如他也指出的那样。
I added the following and my CURL GET requests were working..Hooray.
我添加了以下内容并且我的 CURL GET 请求正在工作......万岁。
AppConfig.java
应用程序配置文件
@Configuration
@ComponentScan(basePackages = "com.app")
public class AppConfig {
@Bean
public AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter()
{
final AnnotationMethodHandlerAdapter annotationMethodHandlerAdapter = new AnnotationMethodHandlerAdapter();
final MappingHymansonHttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymansonHttpMessageConverter();
HttpMessageConverter<?>[] httpMessageConverter = { mappingHymansonHttpMessageConverter };
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter);
annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods);
return annotationMethodHandlerAdapter;
}
}
curl -i -H "Content-Type:application/json" -H "Accept:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 26 Apr 2012 21:19:55 GMT
[{"id":1,"pan":111}]
But the following CURL POST was still not working (Never hitting the controller action and giving no console debug info.
但是下面的 CURL POST 仍然不起作用(从不点击控制器操作并且没有提供控制台调试信息。
curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchaseMe -d "{"id":2,"pan":122}"
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Thu, 26 Apr 2012 21:29:56 GMT
Connection: close
The request sent by the client was syntactically incorrect ().
So I added Logbackto get some detailed debugging started.
所以我添加了Logback来开始一些详细的调试。
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/home/thomas/springApps/purchaseapi.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.hibernate" level="DEBUG" />
<logger name="org.springframework" level="TRACE" />
<logger name="org.springframework.transaction" level="INFO" />
<logger name="org.springframework.security" level="INFO" /> <!-- to debug security related issues (DEBUG) -->
<logger name="org.springframework.web.servlet.mvc" level="TRACE" /> <!-- some serialization issues are at trace level here: org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod -->
<!-- our service -->
<logger name="com.app" level="DEBUG" />
<!-- <logger name="com.app" level="INFO" /> --><!-- to follow if setup is being executed -->
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Adding TRACE level debugging to org.springframework.web.servlet.mvcgave me the answer to the problem.
将 TRACE 级别的调试添加到org.springframework.web.servlet.mvc给了我问题的答案。
2012-04-28 14:17:44,579 DEBUG [http-bio-8080-exec-3] o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor [AbstractMessageConverterMethodArgumentResolver.java:117] Reading [com.app.model.Purchase] as "application/json" using [org.springframework.http.converter.json.MappingHymansonHttpMessageConverter@74a14fed]
2012-04-28 14:17:44,604 TRACE [http-bio-8080-exec-3] o.s.w.s.m.m.a.ServletInvocableHandlerMethod [InvocableHandlerMethod.java:159] Error resolving argument [0] [type=com.app.model.Purchase]
HandlerMethod details:
Controller [com.app.controller.PurchaseController]
Method [public void com.app.controller.PurchaseController.create(com.app.model.Purchase)]
org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected character ('p' (code 112)): was expecting double-quote to start field name
I changed my CURL POSTs to the following an it all worked:
我将我的 CURL POST 更改为以下所有内容:
curl -i -X POST -H "Content-Type:application/json" http://localhost:8080/PurchaseAPIServer/api/purchase -d '{"pan":11111}'
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Sat, 28 Apr 2012 13:19:40 GMT
Hopefully someone finds this useful.
希望有人觉得这很有用。
回答by sdouglass
If I recall correctly the Spring docs say that Spring MVC will automatically detect Hymanson on the classpath and set up a MappingHymansonHttpMessageConverter to handle conversion to/from JSON, but I think I have experienced situations where I had to manually/explictly configure that converter to get things to work. You may want to try adding this to your MVC config XML:
如果我没记错的话,Spring 文档说 Spring MVC 会自动检测类路径上的 Hymanson 并设置一个 MappingHymansonHttpMessageConverter 来处理与 JSON 的转换,但我想我遇到过必须手动/显式配置该转换器才能获得的情况工作的事情。您可能想尝试将其添加到您的 MVC 配置 XML 中:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingHymansonHttpMessageConverter">
</list>
</property>
</bean>
UPDATE: It was this plus properly formatting the JSON being posted, see https://stackoverflow.com/a/10363876/433789
更新:正是这个加上正确格式化正在发布的 JSON,请参阅https://stackoverflow.com/a/10363876/433789
回答by yoram givon
Its 2014 and I wanted to add a few updates to this question which helped me solve the same problem.
它是 2014 年,我想为这个问题添加一些更新,这帮助我解决了同样的问题。
Code update to replace deprecated AnnotationMethodHandlerAdapter in Spring 3.2
@Configuration public class AppConfig {@Bean public RequestMappingHandlerAdapter annotationMethodHandlerAdapter() { final RequestMappingHandlerAdapter annotationMethodHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingHymanson2HttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymanson2HttpMessageConverter(); List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>(); httpMessageConverter.add(mappingHymansonHttpMessageConverter); String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter); annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods); return annotationMethodHandlerAdapter; } }HTTP/1.1 415 Unsupported Media Type error
代码更新以替换 Spring 3.2 中已弃用的 AnnotationMethodHandlerAdapter
@Configuration public class AppConfig {@Bean public RequestMappingHandlerAdapter annotationMethodHandlerAdapter() { final RequestMappingHandlerAdapter annotationMethodHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingHymanson2HttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymanson2HttpMessageConverter(); List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>(); httpMessageConverter.add(mappingHymansonHttpMessageConverter); String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; annotationMethodHandlerAdapter.setMessageConverters(httpMessageConverter); annotationMethodHandlerAdapter.setSupportedMethods(supportedHttpMethods); return annotationMethodHandlerAdapter; } }HTTP/1.1 415 不支持的媒体类型错误
After spending many hours trying to figure out why I am STILL GETTING a 415 error even after adding the correct JSON configuration I finally realized that the problem was NOT with the server side but with the client side. In order for Spring to accept your JSON you MUST make sure that you are sending both "Content-Type : application/json" and "Accept: application/json" as part of your http headers. for me specifically it was an android application HttpUrlConnection which I had to set as:
在花了很多时间试图弄清楚为什么即使添加了正确的 JSON 配置后我仍然收到 415 错误后,我终于意识到问题不在于服务器端,而在于客户端。为了让 Spring 接受您的 JSON,您必须确保将“Content-Type : application/json”和“Accept: application/json”作为 http 标头的一部分发送。对我而言,它是一个 android 应用程序 HttpUrlConnection,我必须将其设置为:
public static String doPost(final String urlString,final String requestBodyString) throws IOException {
final URL url = new URL(urlString);
final HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(15000 /* milliseconds */);
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setChunkedStreamingMode(0);
urlConnection.connect();
final PrintWriter out = new PrintWriter(urlConnection.getOutputStream());
out.print(requestBodyString);
out.close();
final InputStream in = new BufferedInputStream(urlConnection.getInputStream());
final String response = readIt(in);
in.close(); //important to close the stream
return response;
} finally {
urlConnection.disconnect();
}
}
回答by HankCa
Here is a unit test solution similar to yoram givon's answer - https://stackoverflow.com/a/22516235/1019307.
这是类似于 yoram givon 的答案的单元测试解决方案 - https://stackoverflow.com/a/22516235/1019307。
public class JSONFormatTest
{
MockMvc mockMvc;
// The controller used doesn't seem to be important though YMMV
@InjectMocks
ActivityController controller;
@Before
public void setup()
{
MockitoAnnotations.initMocks(this);
this.mockMvc = standaloneSetup(controller).setMessageConverters(new MappingHymanson2HttpMessageConverter())
.build();
}
@Test
public void thatSaveNewDataCollectionUsesHttpCreated() throws Exception
{
String jsonContent = getHereJSON02();
this.mockMvc
.perform(
post("/data_collections").content(jsonContent).contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isCreated());
}
private String getHereJSON01()
{
return "{\"dataCollectionId\":0,\"name\":\"Sat_016\",\"type\":\"httpUploadedFiles\"," ...
}
}
Run the unit test and the print()should print out the MockHttpServletRequest including the Exception.
运行单元测试,print()应该打印出 MockHttpServletRequest 包括异常。
In Eclipse (not sure about how to do this in other IDEs), click on the Exception link and a properties dialog for that exception should open. Tick the 'enabled' box to break on that exception.
在 Eclipse 中(不确定如何在其他 IDE 中执行此操作),单击“异常”链接,应打开该异常的属性对话框。勾选“启用”框以中断该异常。
Debug the unit test and Eclipse will break on the exception. Inspecting it should reveal the problem. In my case it was because I had two of the same entity in my JSON.
调试单元测试,Eclipse 将因异常而中断。检查它应该会发现问题。就我而言,这是因为我的 JSON 中有两个相同的实体。
回答by Diego Sevilla
Try adding a descriptor of what's in your POST request. That is, add to curlthe header:
尝试添加 POST 请求中内容的描述符。也就是说,添加到curl标题:
Content-Type: application/json
If you don't add it, curlwill use the default text/htmlregardless of what you actually send.
如果您不添加它,无论您实际发送什么,curl都将使用默认值text/html。
Also, in PurchaseController.create()you have to add that the type accepted is application/json.
此外,PurchaseController.create()您必须添加接受的类型是application/json.
回答by Nisarg Panchal
I had the same problem, which was solved by two changes in my code :
我有同样的问题,通过我的代码中的两个更改解决了:
- Missing @PathVariable in my method argument, my method didn't have any
Following method in my SpringConfig class since the one I had with handler interceptor was deprecated and giving some issue:
public RequestMappingHandlerAdapter RequestMappingHandlerAdapter() { final RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingHymansonHttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymansonHttpMessageConverter(); final String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; requestMappingHandlerAdapter.getMessageConverters().add(0, mappingHymansonHttpMessageConverter); requestMappingHandlerAdapter.setSupportedMethods(supportedHttpMethods); return requestMappingHandlerAdapter; }
- 在我的方法参数中缺少 @PathVariable,我的方法没有任何
我的 SpringConfig 类中的以下方法,因为我使用处理程序拦截器的方法已被弃用并出现了一些问题:
public RequestMappingHandlerAdapter RequestMappingHandlerAdapter() { final RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter(); final MappingHymansonHttpMessageConverter mappingHymansonHttpMessageConverter = new MappingHymansonHttpMessageConverter(); final String[] supportedHttpMethods = { "POST", "GET", "HEAD" }; requestMappingHandlerAdapter.getMessageConverters().add(0, mappingHymansonHttpMessageConverter); requestMappingHandlerAdapter.setSupportedMethods(supportedHttpMethods); return requestMappingHandlerAdapter; }
回答by tonywu
I experienced once and finally solved it by adding the jar file Hymanson-mapper-asl.jar. Go check if you have included all these dependencies although the exception itself does not tell u that.
经历过一次,最后通过添加jar文件Hymanson-mapper-asl.jar解决了。尽管异常本身并没有告诉您,但请检查您是否已包含所有这些依赖项。
And you really don't need to explicitly configure the bean, and you don't need to put "consumes" in @RequestMapping statement. I'm using Spring 3.1 btw.
而且您确实不需要显式配置bean,也不需要在@RequestMapping 语句中放置“consumes”。顺便说一句,我正在使用 Spring 3.1。
contentType : "application/json" is the only one you need to configure. yes, client side.
contentType : "application/json" 是你唯一需要配置的。是的,客户端。
回答by Roberto
Try to add the following code in your app configuration
尝试在您的应用配置中添加以下代码
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter">
<property name="objectMapper" ref="HymansonObjectMapper" />
</bean>
</mvc:message-converters>
回答by Alex Alekhin
I had the same problem and I resolved it.
我有同样的问题,我解决了它。
1 add MappingHymanson2HttpMessageConverter as described in that thread (see also section 4 http://www.baeldung.com/spring-httpmessageconverter-rest)
1 添加 MappingHymanson2HttpMessageConverter 如该线程中所述(另请参阅第 4 节http://www.baeldung.com/spring-httpmessageconverter-rest)
2 use correct command (with escape symbols):
2 使用正确的命令(带转义符):
curl -i -X POST -H "Content-Type:application/json" -d "{\"id\":\"id1\",\"password\":\"password1\"}" http://localhost:8080/user

