我正在使用ServiceStack构建REST Web服务。我想允许跨域请求,所以我注册了CorsFeature插件。
我的AppHost看起来如下:
public class HomeAppHost : AppHostHttpListenerBase
{
public Context Context { get; set; }
public HomeAppHost(Context context)
: base("HomeAutomation", typeof(HomeInterfaceService).Assembly)
{
Context = context;
}
public override void Configure(Funq.Container container)
{
Plugins.Add(new CorsFeature());
Routes
.Add<HomeInterface>("/HomeInterface")
.Add<HomeInterface>("/HomeInterface/{Id}")
.Add<ViewModel>("/ViewModel")
.Add<FunctionInput>("/Function")
;
}
}
然后,当对服务发出OPTIONS请求时,会导致405方法不允许:
请求:
OPTIONS /Function HTTP/1.1
Host: localhost:1337
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0 FirePHP/0.7.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: nl,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Origin: http://localhost
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
x-insight: activate
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
响应:
HTTP/1.1 405 Method Not Allowed
Content-Length: 1837
Content-Type: application/xml
Server: Microsoft-HTTPAPI/2.0
Date: Fri, 15 Feb 2013 20:19:33 GMT
修改
向服务添加一个空的Options方法确实可以防止405被触发。但是,答案似乎是空的:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 16 Feb 2013 08:44:21 GMT
添加以下内容也会给我一个空的回复:
RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.HttpMethod == "OPTIONS")
httpRes.End();
});
我不得不将httpReq.Method更改为httpReq.HttpMethod,将httpRes.EndServiceStackRequest()更改为httpRes.End()。它是否正确?
答案 0 :(得分:2)
405 表示该方法尚未实施。
因此您需要为Options
动词添加处理程序。方法体可以是空的,例如:
public MyService : Service
{
public void Options(HomeInterface request) {}
}
如果您想要允许所有选项请求(即无论它是哪种服务),您都可以注册一个全局请求过滤器,如:
this.RequestFilters.Add((httpReq, httpRes, requestDto) => {
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.Method == "OPTIONS")
httpRes.EndServiceStackRequest();
});
如果您希望对处理Option请求的方式进行更细粒度的控制,则可以在Filter Attributes中使用相同的逻辑。
答案 1 :(得分:2)
不确定这是否是正确的方法,但我现在正在使用请求过滤器处理CORS:
RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
httpRes.AddHeader("Access-Control-Allow-Origin", "*");
if (httpReq.HttpMethod == "OPTIONS")
{
httpRes.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
httpRes.AddHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
httpRes.End();
}
});
答案 2 :(得分:2)
我对这种行为感到有点困惑。不想在每个服务上创建虚拟的Options()方法,并在每个Dto类上添加虚假路由。 所有我需要的 - ServiceStack AppHost响应每个URL上的每个'OPTIONS'请求,具有相同的行为。 所以这就是我的结局。
为Options创建了我自己的处理程序:
public class OptionsRequestHandler : IHttpHandler, IServiceStackHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
ProcessRequest(null, new HttpResponseWrapper(context.Response), null);
}
public void ProcessRequest(IHttpRequest httpReq, IHttpResponse httpRes, string operationName)
{
httpRes.EndServiceStackRequest();
return;
}
}
然后在主机配置方法中添加它:
this.CatchAllHandlers.Add((httpMethod, pathInfo, filePath) =>
{
if ("OPTIONS".Equals(httpMethod, System.StringComparison.InvariantCultureIgnoreCase))
return new OptionsRequestHandler();
else return null;
});
肯定没有忘记CorsFeature:
host.Plugins.Add(new ServiceStack.ServiceInterface.Cors.CorsFeature());
因此,无论url,dto和服务声明如何,ServiceStack都会在每个带有“OPTIONS”标头的请求上以“200 OK”响应。