Java Spark 请求的路由 [/users/] 尚未映射到 Spark 中以供接受:[*/*]

Java Spark The requested route [/users/] has not been mapped in Spark for Accept: [*/*]

我有以下方法来修改我的 Postgres 数据库中的用户:

public void modifyUser(User usr){
    try (Connection conn = sql2o.beginTransaction()){
        conn.createQuery("update public.\"user\" set name=:name, lastname=:lastname, email=:email where id=:id")
                .addParameter("id", usr.getId())
                .addParameter("name", usr.getName())
                .addParameter("lastname", usr.getLastname())
                .addParameter("email", usr.getEmail())
                .executeUpdate();
        conn.commit();
    }
}

这个方法调用的是:

//update
    put("/users", (request, response) -> {
        response.type("application/json");
        User user = new Gson().fromJson(request.body(), User.class);
        model.modifyUser(user);
        return new Gson().toJson(response);
    });

我用Postman来指定正文,这样:

{   "id": 3, 
"name": "Mary",
"lastname": "Changed",
"email": "email"
}

但是,即使 post 方法工作正常,此 "put" 操作也会引发以下错误:

spark.http.matching.MatcherFilter - The requested route [/users/] has not been mapped in Spark for Accept: [*/*]

我不明白错误是什么。我找不到任何解决方案。

不知道具体原因,但问题出在

put("/users", (request, response) -> {

在这种情况下,Spark 希望将其写成

put("/users/", (request, response) -> {

与接受第一个版本的 "post" 方法不同。

我知道这是一个旧话题,但我希望提供一些关于该主题的额外信息。

路径的“/users”和“/users/”是 2 条不同的路径,因此可以选择允许 2 条不同的 spark 路由(在我看来,spark 实际上做得很好)。

下面是我通常如何在我的 spark 服务器中解决这个 [双关语,不是抱歉] 的示例,当我不希望这些有 2 条不同的路由时:

path("/user", () ->
{
    get("", GenericRoutes.redirectToSlashIndex);
    get("/index.html", GenericRoutes.pathGet_index);
    get("/*", GenericRoutes.redirectToIndex);
});

这里的想法是第一个 ("") 发送到第二个 ("/index.html"),第三个 ("/*") 将任何不存在的路径发送到第二个 (" /index.html") 还有。

然后在通用路由中 class 你会得到类似的东西:

public static final Route redirectToIndex = new Route()
        {
            @Override
            public Object handle(Request request, Response response) throws Exception
            {
                String path = request.pathInfo();
                path = path.substring(0, path.lastIndexOf('/')+1)+"index.html";
                response.redirect(path, 301);
                return "<html>Redirecting...</html>";
            }
        };

public static final Route redirectToSlashIndex = new Route()
        {
            @Override
            public Object handle(Request request, Response response) throws Exception
            {
                response.redirect(request.pathInfo() + "/index.html", 301);
                return "<html>Redirecting...</html>";
            }
        };

我已经简化了我通常在这里做的一些事情(您可能需要在这些路由中进行更多错误处理,并通过 'before' 在这些路由之外进行身份验证检查)。然而,这是一个如何工作的小例子:

  • Nav: "/users" -> 调用 get("",...) -> 重定向到:"/users/index.html"
  • Nav: "/users/" -> 调用 get("/*",...) -> 重定向到:"/users/index.html"
  • Nav: "/users/index.html" -> 调用 get("/index.html",...) -> 没有重定向。

所以您可以看到如何使用类似的东西将流量发送到您期望的地方。但是,请记住一些事项:

  1. 当你有 URL params/tokens 时使用它可能会有问题(如果你不小心,你可能会丢失它们)
  2. 顺序很重要,因为如果“/*”在“/index.html”之前,那么“/users/index.html”将始终触发“/*”(并无限重定向) 而不是触发“/index.html”
  3. 的路由
  4. 在我的示例中,我使用的是 get,因此这种方法通常是预期的(保存 #1),但是对于其他方法(例如 put/post),像这样更改路径可能会导致意外的结果,所以在使用这种方法时要小心,不要将流量重定向到意外的端点。
  5. 如果 SEO 对您很重要,您可以考虑使用我在上面描述为 301 的方法来向正在抓取您网站的人提示您的输出 URL 是永久重定向。这可能比只为所有端点放置相同的路由更可取(这也是一个有效的替代方案[见下文])。

我的有意比你的复杂一点,下面是你可以如何处理你的:

path("/user", () ->
{
    /*Looks like you mentioned you had a post with the 'first version', so I think like this?*/
    post("", UserRoutes.postUsers); //post: /users
    put("", UserRoutes.putUsers); //put: /users
    put("/*", UserRoutes.putUsers); //put: /users/
});

请注意,在上面的最后一个放置示例中,您可以使用“/*”或仅使用“/”。使用 * 您将捕获任何以“/users/”开头的路径,而没有 * 您将只允许“/users/”通过。因此,使用 * 你可以执行“/users/e13a319e-16d9-3ff5-a83c-96564007998e”,它会触发端点,但如果没有 *,相同的路径将失败,这与上面的 #1 直接相关。

因此,您使用哪种方法实际上取决于您网站的意图以及您做什么或不希望那些点击您的端点的人做什么和看到什么。编码愉快!