对于我发出的每个POST请求,Restlet都返回HTTP 415

时间:2015-06-22 12:05:05

标签: json rest post restlet restlet-2.0

每次尝试将数据发布到服务器时,我都会收到此错误:

enter image description here

服务器日志:

Starting the internal [HTTP/1.1] server on port 9192
Starting facilitymanager.api.rest.FacilityManagerAPIRestWrapper application
2015-06-22  13:18:11    127.0.0.1   -   -   9192    POST    /devices/rename -   415 554 45  64  http://localhost:9192   Java/1.7.0_79   -
Stopping the internal server

但是在服务处理程序中,我正在声明我将处理JSON消息,如您所见:

public static final class RenameDevice extends ServerResource {

    @Post("application/json")
    public String doPost() throws InterruptedException, ConstraintViolationException, InvalidChoiceException, JSONException {
        configureRestForm(this);
        final String deviceId = getRequest().getAttributes().get("device_id").toString();
        final String newName = getRequest().getAttributes().get("new_name").toString();
        return renameDevice(deviceId, newName).toString(4);
    }
}

/**
     * Enables incoming connections from different servers.
     * 
     * @param serverResource
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    private static Series<Header> configureRestForm(ServerResource serverResource) {
        Series<Header> responseHeaders = (Series<Header>) serverResource.getResponse().getAttributes()
                .get("org.restlet.http.headers");
        if (responseHeaders == null) {
            responseHeaders = new Series(Header.class);
            serverResource.getResponse().getAttributes().put("org.restlet.http.headers", responseHeaders);
        }
        responseHeaders.add("Access-Control-Allow-Origin", "*");
        responseHeaders.add("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
        responseHeaders.add("Access-Control-Allow-Headers", "Content-Type");
        responseHeaders.add("Access-Control-Allow-Credentials", "false");
        responseHeaders.add("Access-Control-Max-Age", "60");
        return responseHeaders;
    }

我在这里缺少什么?

谢谢!

编辑:这是有关请求的完整日志:

Processing request to: "http://localhost:9192/devices/rename"
Call score for the "org.restlet.routing.VirtualHost@54594d1d" host: 1.0
Default virtual host selected
Base URI: "http://localhost:9192". Remaining part: "/devices/rename"
Call score for the "" URI pattern: 0.5
Selected route: "" -> facilitymanager.api.rest.FacilityManagerAPIRestWrapper@d75d3d7
Starting facilitymanager.api.rest.FacilityManagerAPIRestWrapper application
No characters were matched
Call score for the "/devices/list" URI pattern: 0.0
Call score for the "/groups/rename" URI pattern: 0.0
Call score for the "/devices/rename" URI pattern: 1.0
Selected route: "/devices/rename" -> Finder for RenameDevice
15 characters were matched
New base URI: "http://localhost:9192/devices/rename". No remaining part to match
Delegating the call to the target Restlet
Total score of variant "[text/html]"= 0.25
Total score of variant "[application/xhtml+xml]"= 5.0E-4
Converter selected for StatusInfo: StatusInfoHtmlConverter
2015-06-22  13:28:31    127.0.0.1   -   -   9192    POST    /devices/rename -   415 554 45  67  http://localhost:9192   Java/1.7.0_79   -
POST /devices/rename HTTP/1.1 [415  Unsupported Media Type] ()
KeepAlive stream used: http://localhost:9192/devices/rename
sun.net.www.MessageHeader@2bf4dee76 pairs: {null: HTTP/1.1 415 Unsupported Media Type}{Content-type: text/html; charset=UTF-8}{Content-length: 554}{Server: Restlet-Framework/3.0m1}{Accept-ranges: bytes}{Date: Mon, 22 Jun 2015 12:28:31 GMT}

要获得完整日志,必须在打开restlet /组件服务器之前在任何地方调用此行代码:

// Create a new Component.
component = new Component();
// Add a new HTTP server listening on default port.
component.getServers().add(Protocol.HTTP, SERVER_PORT);
Engine.setLogLevel(Level.ALL); /// <----- HERE
component.start();

2 个答案:

答案 0 :(得分:2)

我发现了问题!问题是标记的@Post方法必须接收参数

所以方法应该是这样的:

@Post("application/json")
        public String doPost(Representation entity) throws InterruptedException, ConstraintViolationException,
                InvalidChoiceException, JSONException, IOException {
            configureRestForm(this);
            final Reader r = entity.getReader();
            StringBuffer sb = new StringBuffer();
            int c;
            // Reads the JSON from the input stream
            while ((c = r.read()) != -1) {
                sb.append((char) c);
            }
            System.out.println(sb.toString()); // Shows the JSON received
        }
    }

Representation entity 参数为您提供检测您正在接收的媒体类型的方法。但由于我的标签如 @Post(“application / json”),我不需要再次验证。

想象一下,我只使用“@ Post”而不是“@ Post(”application / json“)”,我必须验证媒体类型(或这种方式:

@Post
public Representation doPost(Representation entity)
        throws ResourceException {
    if (entity.getMediaType().isCompatible(MediaType.APPLICATION_JSON)) {
       // ...
    }
    // ...
}

答案 1 :(得分:1)

使用@Post注释的方法不需要接收参数,除非您打算从请求中接收有效负载。

如果要过滤传入表示的媒体类型,请使用&#34; json&#34;快捷方式,如下:

@Post("json")

这将阻止您测试表示的媒体类型。

此处提供所有可用快捷方式的列表。其中大多数都很容易记住。使用快捷方式(或&#34;扩展名&#34;例如文件扩展名)的主要原因是&#34; xml&#34;与几种媒体类型有关(application / xml,text / xml)。

如果您想获得表示的完整内容,只需调用&#34; getText()&#34;方法,而不是使用getReader()并使用它。

如果你想支持CORS,我建议你使用CorsService(可以在Restlet Framework的2.3版本中找到。

请注意,存在从请求或响应中获取标头的快捷方式,只需调用&#34; getHeaders()&#34;方法

请注意,存在一个获取从URL获取属性的快捷方式,只需调用&#34; getAttribute(String)方法。

以下是源代码的更新版本:

公共类TestApplication扩展了Application {

    public final static class TestPostResource extends ServerResource {
    @Post
    public String doPost(Representation entity) throws Exception {
        final String deviceId = getAttribute("device_id");
        final String newName = getAttribute("new_name");

        System.out.println(entity.getText());
        System.out.println(getRequest().getHeaders());
        System.out.println(getResponse().getHeaders());

        return deviceId + "/" + newName;
    }
    }

    public static void main(String[] args) throws Exception {
    Component c = new Component();
    c.getServers().add(Protocol.HTTP, 8183);
    c.getDefaultHost().attach(new TestApplication());
    CorsService corsService = new CorsService();
    corsService.setAllowedOrigins(new HashSet<String>(Arrays.asList("*")));
    corsService.setAllowedCredentials(true);
    corsService.setSkippingResourceForCorsOptions(true);

    c.getServices().add(corsService);
    c.start();
    }

    @Override
    public Restlet createInboundRoot() {
    Router router = new Router(getContext());
    router.attach("/testpost/{device_id}/{new_name}", TestPostResource.class);
    return router;
    }

}