Servicestack CorsFeature全局选项处理程序不在某些路由上触发;

giz*_*boy 8 servicestack

我有使用CorsFeature服务的设置,以及正在使用的文件APPHOST使用的函数收集到mythz在其他的答案提出的办法,:

private void ConfigureCors(Funq.Container container)
{
    Plugins.Add(new CorsFeature(allowedOrigins: "*",
                                allowedMethods: "GET, POST, PUT, DELETE, OPTIONS",
                                allowedHeaders: "Content-Type, Authorization, Accept",
                                allowCredentials: true));

    PreRequestFilters.Add((httpReq, httpRes) =>
    {
        //Handles Request and closes Responses after emitting global HTTP Headers
        if (httpReq.HttpMethod == "OPTIONS")
        {
            httpRes.EndRequest();
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

但是,预请求过滤器仅针对某些服务请求触发.我们在服务中拥有的一个基本实体是一个问题实体,并且定义的自定义路由如下:

[Route("/question")]
[Route("/question/{ReviewQuestionId}", "GET,DELETE")]
[Route("/question/{ReviewQuestionId}/{ReviewSectionId}", "GET")]
Run Code Online (Sandbox Code Playgroud)

使用POSTMAN触发测试查询(全部使用OPTIONS动词),我们可以看到这将触发预请求过滤器:

http://localhost/myservice/api/question/
Run Code Online (Sandbox Code Playgroud)

但这不会:

http://localhost/myservice/api/question/66
Run Code Online (Sandbox Code Playgroud)

据推测,这是因为第二和第三条路线明确定义了它们接受的动词,OPTIONS不是其中之一.

是否真的有必要在限制所支持的动词的每个定义路线中拼出OPTIONS?

myt*_*thz 7

PreRequestFilters仅针对不排除OPTIONS的有效路由触发(例如,通过离开Verbs=null并允许它处理所有动词 - inc.OPTIONS).

为了能够处理所有OPTIONS请求(即使对于非匹配路由),您需要在Request管道开头(即在路由匹配之前)处理请求Config.RawHttpHandlers.这是在CorsFeature中为您在ServiceStack的下一个主要(v4)版本中完成的:

//Handles Request and closes Response after emitting global HTTP Headers
var emitGlobalHeadersHandler = new CustomActionHandler(
    (httpReq, httpRes) => httpRes.EndRequest());

appHost.RawHttpHandlers.Add(httpReq =>
    httpReq.HttpMethod == HttpMethods.Options
        ? emitGlobalHeadersHandler
        : null); 
Run Code Online (Sandbox Code Playgroud)

V3中不存在CustomActionHandler,但可以使用以下命令轻松创建:

public class CustomActionHandler : IServiceStackHttpHandler, IHttpHandler 
{
    public Action<IHttpRequest, IHttpResponse> Action { get; set; }

    public CustomActionHandler(Action<IHttpRequest, IHttpResponse> action)
    {
        if (action == null)
            throw new Exception("Action was not supplied to ActionHandler");

        Action = action;
    }

    public void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
    {            
        Action(httpReq, httpRes);
    }

    public void ProcessRequest(HttpContext context)
    {
        ProcessRequest(context.Request.ToRequest(GetType().Name), 
            context.Response.ToResponse(),
            GetType().Name);
    }

    public bool IsReusable
    {
        get { return false; }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用Fallback处理程序

匹配所有路由的另一种方法是指定FallbackRoute,例如,处理可以向Fallback路由添加通配符的所有路由:

[FallbackRoute("/{Path*}")]
public class Fallback
{
    public string Path { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

但由于它匹配所有未处理的路由,因此不再为非匹配请求提供404,因为现在匹配所有未匹配的路由.但您可以通过以下方式手动轻松处理:

public class FallbackService : Service
{
    public object Any(Fallback request)
    {
        if (base.Request.HttpMethod == "OPTIONS")
            return null;

        throw HttpError.NotFound("{0} was not found".Fmt(request.Path));
    }
}
Run Code Online (Sandbox Code Playgroud)