I wrote a Web API in Java (JAX-RS by Jersey) which returns "403 Forbidden" with JSON.
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=UTF-8
...
{"resultCode":"..."}
It works on the local GAE dev server as expected. However, . 。
HTTP/1.1. 403 Forbidden
Content-Type: text/html; charset=utf-8
...
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
</body></html>
How can I prevent GAE from changing the content type and the entity body?
My endpoint does not throw any exception. It returns a Response instance. The code snippet below is a test endpoint. On the local GAE dev server, this endpoint returns JSON. On the real GAE, it returns HTML. Too much of a good thing.
import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; @Path("/test") public class TestEndpoint { @GET public Response get() { return Response .status(Status.BAD_REQUEST) .type(MediaType.APPLICATION_JSON_TYPE) .entity("{\\"id\\":1}") .build(); } }
I wrote a simpler example code like below. This code returns JSON even on the real GAE! What's the difference?
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setStatus(400); response.setContentType("application/json;charset=UTF-8"); PrintWriter out = response.getWriter(); out.write("{\\"hello\\":\\"world\\"}"); } }
I read Jersey's source code and intuited this answer.
Setting " jersey.config.server.response.setStatusOverSendError " (one of Jersey's server configuration properties ) to true solved the issue.
The following is an excerpt from my new web.xml.
<servlet>
<servlet-name>API</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
......
</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.response.setStatusOverSendError</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
You'll have to define your own exception mapper and payload extensions in your service context file:
<jaxrs:server id="my-resources" address="/some-context-path">
<jaxrs:serviceBeans>
<ref bean="my-resource-1" />
<ref bean="my-resource-2" />
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jaxbProvider" />
<ref bean="my-custom-exception-mapper" />
</jaxrs:providers>
<jaxrs:features>
<cxf:logging/>
</jaxrs:features>
</jaxrs:server>
my-custom-exception-mapper implements ExceptionMapper, ResponseExceptionMapper. Something like this is a good start: http://www.luckyryan.com/2013/06/15/apache-cxf-exception-handler-for-jaxrs-rest/
Mentioned solution without web.xml may look like:
new ResourceConfig()
.property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.