You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

actix_web路由报错:`Vec<TextAnnotation>`未实现`Responder` trait

Actix-web返回Vec<TextAnnotation>提示Responder未实现的问题及解决

问题场景

使用actix_web创建路由时,返回Vec<TextAnnotation>遇到如下编译错误:

the trait `Responder` is not implemented for `Vec<TextAnnotation>`

报错路由代码

use std::str::FromStr;

use actix_web::{http::StatusCode, web::Json, Result};
use mongodb::{
    bson::{doc, oid::ObjectId},
    options::{FindOneAndUpdateOptions, FindOptions, ReturnDocument},
};

use crate::{
    database::mongodb::DB,
    helpers::colors_helpers::{get_next_valid_color, is_color_used, is_valid_color},
    middleware::auth_middleware::UserAuthContext,
    models::text_annotation_model::{
        CreateLabelBody, CreateTextAnnotationBody, CreateTokenBody, Label, TextAnnotation,
        UpdateLabelBody,
    },
    object::{common::Message, error::ApiError},
};

// ...

#[get("/")]
async fn get_annotations(
    page: web::Query<i64>,
    count: web::Query<i64>,
    req: HttpRequest,
) -> Result<Vec<TextAnnotation>, ApiError> {
    let auth = get_auth_ctx(&req);

    let res = AnnotationController::get_page(page.0, count.0, auth);

    if res.is_err() {
        return Err(res.err().unwrap());
    }

    Ok(res.unwrap())
}

已实现的Responder代码

use actix_web::{
    get, post,
    web::{self},
    HttpRequest, Result, Scope,
};

use crate::{
    controllers::annotation_controller::AnnotationController,
    helpers::request_helpers::get_auth_ctx,
    models::text_annotation_model::{CreateTextAnnotationBody, TextAnnotation},
    object::error::ApiError,
};

// ...

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TextAnnotation {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub content: String,
    pub user_id: ObjectId,
    pub tokens: Vec<Token>,
    pub labels: Vec<Label>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Token {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub start: i64,
    pub end: i64,
    /// reference a label in the labels array
    pub label: ObjectId,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Label {
    #[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
    pub id: Option<ObjectId>,
    pub name: String,
    pub color: String,
}

impl Responder for TextAnnotation {
    type Body = BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> {
        HttpResponse::Ok().json(self)
    }
}

impl Responder for Label {
    type Body = BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> {
        HttpResponse::Ok().json(self)
    }
}

impl Responder for Token {
    type Body = BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> {
        HttpResponse::Ok().json(self)
    }
}

问题原因

你只为单个TextAnnotation、Label、Token类型实现了Responder trait,但actix_web不会自动为集合类型(比如Vec<T>)推导实现Responder——即使T已经实现了该trait,集合类型仍需单独处理。

解决方法

方案1:为Vec<TextAnnotation>实现Responder

直接为集合类型实现trait,逻辑与单个元素一致,返回JSON数组:

use actix_web::{Responder, HttpResponse, BoxBody};

impl Responder for Vec<TextAnnotation> {
    type Body = BoxBody;

    fn respond_to(self, _req: &actix_web::HttpRequest) -> HttpResponse<Self::Body> {
        HttpResponse::Ok().json(self)
    }
}

方案2:用Json包装返回值

无需额外实现trait,直接用web::Json包裹Vec<TextAnnotation>——因为Json<T>已默认实现Responder(只要T实现了Serialize,你的TextAnnotation已经通过#[derive(Serialize)]满足条件):

#[get("/")]
async fn get_annotations(
    page: web::Query<i64>,
    count: web::Query<i64>,
    req: HttpRequest,
) -> Result<Json<Vec<TextAnnotation>>, ApiError> {
    let auth = get_auth_ctx(&req);

    let res = AnnotationController::get_page(page.0, count.0, auth);

    if res.is_err() {
        return Err(res.err().unwrap());
    }

    Ok(Json(res.unwrap()))
}

方案3:直接返回HttpResponse

在路由函数中手动构建响应,适合需要自定义状态码、响应头的场景:

#[get("/")]
async fn get_annotations(
    page: web::Query<i64>,
    count: web::Query<i64>,
    req: HttpRequest,
) -> Result<HttpResponse, ApiError> {
    let auth = get_auth_ctx(&req);

    let res = AnnotationController::get_page(page.0, count.0, auth);

    if res.is_err() {
        return Err(res.err().unwrap());
    }

    Ok(HttpResponse::Ok().json(res.unwrap()))
}

内容的提问来源于stack exchange,提问作者Riadh Adrani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:15:16