Actix Web 未处理 post 请求?
Actix Web is not handling post request?
所以我正在尝试创建一个基本的 actix-web 应用程序,它将允许我创建一个非常基本的博客系统。它正在处理我的 GET 请求,但没有处理我的 POST 请求。
main.rs:
use actix_web::{HttpServer, App, web};
use sqlx::postgres::PgPool;
use dotenv::dotenv;
mod posts;
mod database;
#[actix_web::main]
pub async fn main() -> std::io::Result<()>{
dotenv().ok();
let pool = PgPool::connect(&dotenv::var("DATABASE_URL").unwrap()).await.unwrap();
HttpServer::new(move || {
// The scope for all post services
let posts = web::scope("/posts").service(posts::get_all_posts).service(posts::create_post);
App::new()
.data(pool.clone())
.service(web::scope("/api").service(posts))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
posts/routes.rs:
use super::*;
use database::{NewPost, model::Post};
use actix_web::{get, post, Responder, HttpResponse};
#[get("/")]
pub async fn get_all_posts(pool: web::Data<PgPool>) -> impl Responder {
println!("New GET request for all posts!");
let result = Post::find_all(pool.get_ref()).await;
match result {
Ok(posts) => HttpResponse::Ok().json(posts),
_ => HttpResponse::BadRequest().body("Error trying to read all the posts from the database")
}
}
#[post("/new")]
pub async fn create_post(post: web::Json<NewPost>, pool: web::Data<PgPool>) -> impl Responder {
println!("New POST request to create a post!");
let result = Post::new_post(post.into_inner(), pool.as_ref()).await;
match result {
Ok(post) => HttpResponse::Ok().json(post),
_ => HttpResponse::BadRequest().body("Error trying to create a new post")
}
}
database/model.rs:
use serde::{Serialize, Deserialize};
use sqlx::{FromRow, PgPool, Row, postgres::PgRow};
use uuid::Uuid;
use chrono::prelude::*;
/// Struct to represent database record.
#[derive(Serialize, FromRow, Debug)]
pub struct Post {
pub id: Uuid,
pub content: String,
pub created_at: chrono::NaiveDateTime
}
/// Struct to receive user input.
#[derive(Serialize, Deserialize)]
pub struct NewPost {
pub content: String
}
impl Post {
pub async fn find_all(pool: &PgPool) -> std::io::Result<Vec<Post>> {
let mut posts = Vec::new();
let recs = sqlx::query_as!(Post, r#"SELECT id, content, created_at FROM post ORDER BY id"#)
.fetch_all(pool)
.await
.unwrap();
for rec in recs {
posts.push(Post {
id: rec.id,
content: rec.content,
created_at: rec.created_at
});
}
Ok(posts)
}
pub async fn new_post(post: NewPost, pool: &PgPool) -> std::io::Result<Post> {
let mut tx = pool.begin().await.unwrap();
let post = sqlx::query("INSERT INTO post (id, content, created_at) VALUES (, , ) RETURNING id, content, created_at")
.bind(Uuid::new_v4())
.bind(post.content)
.bind(Utc::now())
.map(|row: PgRow| {
Post {
id: row.get(0),
content: row.get(1),
created_at: row.get(2)
}
})
.fetch_one(&mut tx)
.await
.unwrap();
tx.commit().await.unwrap();
Ok(post)
}
}
目前,我正在使用 curl 测试 API。当我想发送 GET 请求时,我使用命令:
curl localhost:8080/api/posts/
当我 运行 此命令时,我的 Rust 应用程序打印出语句:“所有帖子的新 GET 请求!”正如我所料。
当我想发送 POST 请求时,我使用命令:
curl -H "Content-Type: application/json" -X POST -d '{ \
"content": "This is my first post" \
}' localhost:8080/api/posts/new
在 运行 执行此 curl 命令后,我根本没有得到任何输出,curl 终端没有任何输出,我的 rust 程序也没有任何输出。
仔细阅读所有内容,您的卷曲实际上可能是罪魁祸首。
如果您包含 -i
以显示响应 headers,那么您可以看到您实际上收到了 400 错误请求。
$ curl -i -H "Content-Type: application/json" -X POST -d '{ \
> "content": "This is my first post" \
> }' localhost:8080/api/posts/new
HTTP/1.1 400 Bad Request
content-length: 0
date: Sun, 03 Jan 2021 14:04:12 GMT
如果您将 create_post
更改为采用 post: String
而不是 post: web::Json<NewPost>
,则可以更轻松地检查端点正在接收的负载。
pub async fn create_post(post: String) -> impl Responder {
println!("{}", post);
现在执行相同的 curl
显示以下输出:
{ \
"content": "This is my first post" \
}
简而言之,问题是反斜杠保留在负载中。因此,要使其正常工作,您唯一需要做的就是删除反斜杠。
curl -H "Content-Type: application/json" -X POST -d '{
"content": "This is my first post"
}' localhost:8080/api/posts/new
所以我正在尝试创建一个基本的 actix-web 应用程序,它将允许我创建一个非常基本的博客系统。它正在处理我的 GET 请求,但没有处理我的 POST 请求。
main.rs:
use actix_web::{HttpServer, App, web};
use sqlx::postgres::PgPool;
use dotenv::dotenv;
mod posts;
mod database;
#[actix_web::main]
pub async fn main() -> std::io::Result<()>{
dotenv().ok();
let pool = PgPool::connect(&dotenv::var("DATABASE_URL").unwrap()).await.unwrap();
HttpServer::new(move || {
// The scope for all post services
let posts = web::scope("/posts").service(posts::get_all_posts).service(posts::create_post);
App::new()
.data(pool.clone())
.service(web::scope("/api").service(posts))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
posts/routes.rs:
use super::*;
use database::{NewPost, model::Post};
use actix_web::{get, post, Responder, HttpResponse};
#[get("/")]
pub async fn get_all_posts(pool: web::Data<PgPool>) -> impl Responder {
println!("New GET request for all posts!");
let result = Post::find_all(pool.get_ref()).await;
match result {
Ok(posts) => HttpResponse::Ok().json(posts),
_ => HttpResponse::BadRequest().body("Error trying to read all the posts from the database")
}
}
#[post("/new")]
pub async fn create_post(post: web::Json<NewPost>, pool: web::Data<PgPool>) -> impl Responder {
println!("New POST request to create a post!");
let result = Post::new_post(post.into_inner(), pool.as_ref()).await;
match result {
Ok(post) => HttpResponse::Ok().json(post),
_ => HttpResponse::BadRequest().body("Error trying to create a new post")
}
}
database/model.rs:
use serde::{Serialize, Deserialize};
use sqlx::{FromRow, PgPool, Row, postgres::PgRow};
use uuid::Uuid;
use chrono::prelude::*;
/// Struct to represent database record.
#[derive(Serialize, FromRow, Debug)]
pub struct Post {
pub id: Uuid,
pub content: String,
pub created_at: chrono::NaiveDateTime
}
/// Struct to receive user input.
#[derive(Serialize, Deserialize)]
pub struct NewPost {
pub content: String
}
impl Post {
pub async fn find_all(pool: &PgPool) -> std::io::Result<Vec<Post>> {
let mut posts = Vec::new();
let recs = sqlx::query_as!(Post, r#"SELECT id, content, created_at FROM post ORDER BY id"#)
.fetch_all(pool)
.await
.unwrap();
for rec in recs {
posts.push(Post {
id: rec.id,
content: rec.content,
created_at: rec.created_at
});
}
Ok(posts)
}
pub async fn new_post(post: NewPost, pool: &PgPool) -> std::io::Result<Post> {
let mut tx = pool.begin().await.unwrap();
let post = sqlx::query("INSERT INTO post (id, content, created_at) VALUES (, , ) RETURNING id, content, created_at")
.bind(Uuid::new_v4())
.bind(post.content)
.bind(Utc::now())
.map(|row: PgRow| {
Post {
id: row.get(0),
content: row.get(1),
created_at: row.get(2)
}
})
.fetch_one(&mut tx)
.await
.unwrap();
tx.commit().await.unwrap();
Ok(post)
}
}
目前,我正在使用 curl 测试 API。当我想发送 GET 请求时,我使用命令:
curl localhost:8080/api/posts/
当我 运行 此命令时,我的 Rust 应用程序打印出语句:“所有帖子的新 GET 请求!”正如我所料。
当我想发送 POST 请求时,我使用命令:
curl -H "Content-Type: application/json" -X POST -d '{ \
"content": "This is my first post" \
}' localhost:8080/api/posts/new
在 运行 执行此 curl 命令后,我根本没有得到任何输出,curl 终端没有任何输出,我的 rust 程序也没有任何输出。
仔细阅读所有内容,您的卷曲实际上可能是罪魁祸首。
如果您包含 -i
以显示响应 headers,那么您可以看到您实际上收到了 400 错误请求。
$ curl -i -H "Content-Type: application/json" -X POST -d '{ \
> "content": "This is my first post" \
> }' localhost:8080/api/posts/new
HTTP/1.1 400 Bad Request
content-length: 0
date: Sun, 03 Jan 2021 14:04:12 GMT
如果您将 create_post
更改为采用 post: String
而不是 post: web::Json<NewPost>
,则可以更轻松地检查端点正在接收的负载。
pub async fn create_post(post: String) -> impl Responder {
println!("{}", post);
现在执行相同的 curl
显示以下输出:
{ \
"content": "This is my first post" \
}
简而言之,问题是反斜杠保留在负载中。因此,要使其正常工作,您唯一需要做的就是删除反斜杠。
curl -H "Content-Type: application/json" -X POST -d '{
"content": "This is my first post"
}' localhost:8080/api/posts/new