ServiceStack REST API和CORS

47

请问ServiceStack框架是否可以用于创建支持CORS的REST服务?

我已经为WCF REST的相关问题苦苦挣扎了好几天,但完全没有用。


我尝试使用WCF REST Starter Kit和http://dhvik.blogspot.com/2011/06/supporting-cross-origin-resource_9123.html(包括属性和第一个不理想的代码示例),但是我一直收到以下错误信息:Origin http://xxxxx.com未被Access-Control-Allow-Origin允许。 - user156888
https://dev59.com/qWw05IYBdhLWcg3wcReu - L.B
我认为Chrome网络控制台错误地报告了一个取消的请求 - Fiddler没有显示相同的结果 - 它说完成得很好... - user156888
2个回答

88

使用CorsFeature插件

启用全局CORS支持

现在我们有一个CorsFeature,它将CORS头信息封装到下面的插件中,使得在您的ServiceStack服务中添加CORS支持变得更加容易。

通常情况下,只需要这样做:

Plugins.Add(new CorsFeature());

使用默认值:

CorsFeature(allowedOrigins:"*", 
    allowedMethods:"GET, POST, PUT, DELETE, OPTIONS", 
    allowedHeaders:"Content-Type", 
    allowCredentials:false);

您可以省略与默认值匹配的任何值。例如,如果您只想限制允许使用的方法为GET和POST请求,只需执行以下操作:

Plugins.Add(CorsFeature(allowedMethods:"GET, POST"));

为所有OPTION请求全局启用CORS

一旦注册了CorsFeature(或手动注册全局头文件),您可以选择通过添加PreRequest过滤器来发射所有已注册的全局头文件(即CorsFeature中的头文件),并短路所有OPTIONS请求,以启用所有OPTION请求的CORS:

this.PreRequestFilters.Add((httpReq, httpRes) => {
    //Handles Request and closes Responses after emitting global HTTP Headers
    if (httpReq.Method == "OPTIONS") 
        httpRes.EndRequest(); //add a 'using ServiceStack;'
});

启用每个服务的CORS支持

除了使用上面提到的插件之外,ServiceStack还允许您通过使用[EnableCors]响应过滤器属性在每个服务上启用CORS,该属性具有与上述相同的默认值。例如,您可以像上面那样仅启用GET、POST:

[EnableCors(allowedMethods:"GET,POST")]
public class MyService : Service { ... }

手动启用CORS

ServiceStack之美在于它建立在高度灵活和简单的核心之上。我们不尝试在所有内容上构建强类型API,因为无法预测未来会存在哪些新的HTTP Headers / StatusCodes。因此,虽然我们提供了方便的行为以完成常见任务,但我们也提供了一个灵活的API,让您配置任何所需的HTTP输出。

设置全局HTTP头

以下是在您的AppHost配置中全局启用跨域资源共享的方法:

public override void Configure(Container container)
{
    //Permit modern browsers (e.g. Firefox) to allow sending of any REST HTTP Method
    base.SetConfig(new EndpointHostConfig
    {
        GlobalResponseHeaders = {
            { "Access-Control-Allow-Origin", "*" },
            { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
            { "Access-Control-Allow-Headers", "Content-Type" },
        },
    });
}

在服务中返回自定义HTTP头

这些头信息将在每个请求中发送,或者您也可以为特定的Web服务启用它,例如:以Hello World Web Service为例:

public class Hello {
    public string Name { get; set; }
}

public class HelloResponse {
    public string Result { get; set; }
}

public class HelloService : IService 
{
    public object Any(Hello request)
    {
        var dto = new HelloResponse { Result = "Hello, " + request.Name };
        return new HttpResult(dto) {
            Headers = {
              { "Access-Control-Allow-Origin", "*" },
              { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" } 
              { "Access-Control-Allow-Headers", "Content-Type" }, }
        };
    }
}
以上是你需要开发 Web 服务所需的全部 C#代码,然后自动对所有 HTTP 动词(GET、POST 等)和内置终结点进行连接,即 JSON、XML、JSV、HTML、CSV、SOAP 1.1/1.2 - 免费提供,无需任何配置或摩擦。请查看上面的 Web 服务实时示例
除了上述终结点外,每个服务都可用于通过 JSONP 调用(这是在 Ajax 应用程序中启用跨域服务调用的另一种流行方式),其中每个服务可以通过简单地将?callback=cb参数添加到查询字符串中来调用 JSONP,例如: http://www.servicestack.net/ServiceStack.Hello/servicestack/hello/world?callback=cb 这是使用 ServiceStack 提供的灵活性和生产力优势的另一个例子,在您的 Web 服务中,您可以自由地表达自己并且没有任何限制,实际上可以 返回几乎任何内容,并且它会按预期进行序列化。
与 WCF 相比,ServiceStack 不仅更易于使用(具有更多的开箱即用功能),而且还更快,因为其所有组件都经过高度优化以实现最大性能。请参阅性能基准

2
也许我做错了什么,但是在服务类型上使用[EnableCors(allowedMethods:"GET,POST")]似乎不起作用。如果我将其移动并放置在Get()Options()方法上,则可以正常工作。 - Adam Ralph
1
@mythz 我已经按照您的示例在我的 AppHost.cs 中添加了 PreRequestFilters,但是我的 POST 请求仍然没有得到它们所需的标头。 它们的设置如下:https://gist.github.com/JaKXz/8fd6ec1dda2f1b6aef0a --我在同一文件中设置了一个 GET 请求,设置方式相同,可以正常工作。 如果需要更多信息,请告诉我。 - JaKXz
有没有一种简单的方法允许任何标题作为allowedHeaders,而不需要逐个列出每个标题? - Justin
@Justin CorsFeature默认情况下会将它们全部注册,如上面的默认值所示。 - mythz
@mythz 我必须明确列出每个标头,否则我会收到错误。 - Justin
显示剩余2条评论

7

提醒一下,我花了不少时间才找到CORS插件的位置。也许是我太蠢了。

它在ServiceStack.ServiceInterface.Cors中。


3
这就是为什么我喜欢使用 Resharper :) - Gui

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接