Play 框架上的 Web 服务不接受 POST 消息
Web service on Play framework not accepting POST message
我正在从 Angular 服务向播放应用程序发送以下消息
public createUser(user:User):any{
console.log('contacting server at '+this.API_URL +this.ADD_USER_URL +" with user data ",user);
/*http.post returns an observable. The caller's code should subscribe to this observable */
return this.http.post(this.API_URL +this.ADD_USER_URL,user)
.map(response => { //handler if post's Observable is successful. map creates new User and returns Observable<User>.
console.log('response from backend service',response);
//return new User(response); //the constructor of User allows passing an object.
/*when the observable of http.post returns (produces) data (the response), the map function prints a message and returns that response*/
return response;
})
.catch(this.handleError); //error handler if Observable fails
}
我在 Play 的控制台上收到以下警告并禁止响应。
[warn] p.filters.CSRF - [CSRF] Check failed because application/json for request /ws/users/add
WebToBackendInterfaceService::handleError
Object { headers: {…}, status: 403, statusText: "Forbidden", url: "http://localhost:9000/ws/users/add", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:9000/ws/users/add: 403 Forbidden", error: "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>Unauthorized</title>\n <link rel=\"shortcut icon\" href=\"data:image/png;base64,...">\n <style>\n html, body, pre {\n margin: 0;\n padding: 0;\n font-family: Monaco, 'Lucida Console', monospace;\n background: #ECECEC;\n }\n h1 {\n margin: 0;\n background: #333;\n padding: 20px 45px;\n color: #fff;\n text-shadow: 1px 1px 1px rgba(0,0,0,.3);\n border-bottom: 1px solid #111;\n font-size: 28px;\n }\n p#detail {\n margin: 0;\n padding: 15px 45px;\n background: #888;\n border-top: 4px solid #666;\n color: #111;\n text-shadow: 1px 1px 1px rgba(255,255,255,.3);\n font-size: 14px;\n border-bottom: 1px solid #333;\n }\n </style>\n </head>\n <body>\n <h1>Unauthorized</h1>\n\n <p id=\"detail\">\n You must be authenticated to access this page.\n </p>\n\n </body>\n</html>\n" }
Play 的 CSRF 似乎不喜欢这条消息。我该如何解决这个问题?我在 Play 中读到,错误发生在
- 请求不是 GET、HEAD 或 Option - 在我的情况下是正确的,我正在发送 POST 消息
- 请求有 cookie 或授权 header。我没有明确发送它们。 Angular默认发送吗?
- CORS 过滤器未配置为信任请求的来源。 - 我正在向 localhost:9000 发送请求。 Play 不应该信任本地主机吗?
如何让 Play 接受我的消息?
这是一种解决方法。正确的解释在 Angular not sending CSRF token in header 中。基本上,我的客户应该发送一个 CSRF Header,其中包含最初由 play framework
创建的令牌
我不知道这是否正确,但我不得不在 Play 中禁用 CSRF。可以通过以下两种方式完成
在routes
文件中,在规则
上方添加nocsrf
+nocsrf
POST /ws/users/add controllers.UserController.addUser
或在 application.conf
中完全禁用 csrf
play.filters {
# Disabled filters remove elements from the enabled list.
disabled += play.filters.csrf.CSRFFilter
}
我完全禁用了csrf
确保使用 header 设置前端 HTTP 客户端,CSRF 的 cookie 名称 "Csrf-Token". I had the same issue with my Angular+Play seed, turns out Angular's defaults cookie and header names 为 XSRF-TOKEN 和 X-XSRF-TOKEN。所以在我的例子中,我不得不导入另一个 Angular 模块来覆盖这些值:
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'Csrf-Token',
headerName: 'Csrf-Token',
}),
routing
]
尽管禁用 Play 的 CSRF 保护(基于 Manu Chadha 的回答)可能是一种解决方法,但强烈建议不要这样做。
我正在从 Angular 服务向播放应用程序发送以下消息
public createUser(user:User):any{
console.log('contacting server at '+this.API_URL +this.ADD_USER_URL +" with user data ",user);
/*http.post returns an observable. The caller's code should subscribe to this observable */
return this.http.post(this.API_URL +this.ADD_USER_URL,user)
.map(response => { //handler if post's Observable is successful. map creates new User and returns Observable<User>.
console.log('response from backend service',response);
//return new User(response); //the constructor of User allows passing an object.
/*when the observable of http.post returns (produces) data (the response), the map function prints a message and returns that response*/
return response;
})
.catch(this.handleError); //error handler if Observable fails
}
我在 Play 的控制台上收到以下警告并禁止响应。
[warn] p.filters.CSRF - [CSRF] Check failed because application/json for request /ws/users/add
WebToBackendInterfaceService::handleError
Object { headers: {…}, status: 403, statusText: "Forbidden", url: "http://localhost:9000/ws/users/add", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:9000/ws/users/add: 403 Forbidden", error: "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <title>Unauthorized</title>\n <link rel=\"shortcut icon\" href=\"data:image/png;base64,...">\n <style>\n html, body, pre {\n margin: 0;\n padding: 0;\n font-family: Monaco, 'Lucida Console', monospace;\n background: #ECECEC;\n }\n h1 {\n margin: 0;\n background: #333;\n padding: 20px 45px;\n color: #fff;\n text-shadow: 1px 1px 1px rgba(0,0,0,.3);\n border-bottom: 1px solid #111;\n font-size: 28px;\n }\n p#detail {\n margin: 0;\n padding: 15px 45px;\n background: #888;\n border-top: 4px solid #666;\n color: #111;\n text-shadow: 1px 1px 1px rgba(255,255,255,.3);\n font-size: 14px;\n border-bottom: 1px solid #333;\n }\n </style>\n </head>\n <body>\n <h1>Unauthorized</h1>\n\n <p id=\"detail\">\n You must be authenticated to access this page.\n </p>\n\n </body>\n</html>\n" }
Play 的 CSRF 似乎不喜欢这条消息。我该如何解决这个问题?我在 Play 中读到,错误发生在
- 请求不是 GET、HEAD 或 Option - 在我的情况下是正确的,我正在发送 POST 消息
- 请求有 cookie 或授权 header。我没有明确发送它们。 Angular默认发送吗?
- CORS 过滤器未配置为信任请求的来源。 - 我正在向 localhost:9000 发送请求。 Play 不应该信任本地主机吗?
如何让 Play 接受我的消息?
这是一种解决方法。正确的解释在 Angular not sending CSRF token in header 中。基本上,我的客户应该发送一个 CSRF Header,其中包含最初由 play framework
创建的令牌我不知道这是否正确,但我不得不在 Play 中禁用 CSRF。可以通过以下两种方式完成
在routes
文件中,在规则
nocsrf
+nocsrf
POST /ws/users/add controllers.UserController.addUser
或在 application.conf
play.filters {
# Disabled filters remove elements from the enabled list.
disabled += play.filters.csrf.CSRFFilter
}
我完全禁用了csrf
确保使用 header 设置前端 HTTP 客户端,CSRF 的 cookie 名称 "Csrf-Token". I had the same issue with my Angular+Play seed, turns out Angular's defaults cookie and header names 为 XSRF-TOKEN 和 X-XSRF-TOKEN。所以在我的例子中,我不得不导入另一个 Angular 模块来覆盖这些值:
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
HttpClientXsrfModule.withOptions({
cookieName: 'Csrf-Token',
headerName: 'Csrf-Token',
}),
routing
]
尽管禁用 Play 的 CSRF 保护(基于 Manu Chadha 的回答)可能是一种解决方法,但强烈建议不要这样做。