问题
I'm building a REST webservice using ServiceStack. I want to allow cross-domain request, so I registered the CorsFeature plugin.
My AppHost looks as follows:
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")
;
}
}
Then, when an OPTIONS request is made to the service, it results in a 405 Method Not Allowed:
Request:
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
Response:
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
Edit
Adding an empty Options method to the service does indeed prevent the 405 from being triggered. However, the response seems to be empty:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Server: Microsoft-HTTPAPI/2.0
Date: Sat, 16 Feb 2013 08:44:21 GMT
Adding the following also gives me an empty response:
RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.HttpMethod == "OPTIONS")
httpRes.End();
});
I had to change httpReq.Method to httpReq.HttpMethod and httpRes.EndServiceStackRequest() to httpRes.End(). Is this correct?
回答1:
405 in ServiceStack means that method has not been implemented.
So you need to add a handler for the Options
verb. The method body can be empty, e.g:
public MyService : Service
{
public void Options(HomeInterface request) {}
}
If you wanted to allow all Options requests (i.e. regardless of which service it is), you can register a global request filter like:
this.RequestFilters.Add((httpReq, httpRes, requestDto) => {
//Handles Request and closes Responses after emitting global HTTP Headers
if (httpReq.Method == "OPTIONS")
httpRes.EndServiceStackRequest();
});
You can use the same logic in Filter Attributes if you want more fine-grained control over how Option requests are handled.
回答2:
Not sure whether this is the right way to go, but I'm now handling the CORS myself using a request filter:
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();
}
});
回答3:
I was a bit confused about this behavior. Did not wanted to make dummy Options() methods on every service and add fake routes on every Dto class. All I've needed - that ServiceStack AppHost responsed for EVERY 'OPTIONS' request, on every url, with same behavior. So this is what I've ended with.
Created my own handler for 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;
}
}
Then added it in host Configure method:
this.CatchAllHandlers.Add((httpMethod, pathInfo, filePath) =>
{
if ("OPTIONS".Equals(httpMethod, System.StringComparison.InvariantCultureIgnoreCase))
return new OptionsRequestHandler();
else return null;
});
And surely did not forget the CorsFeature:
host.Plugins.Add(new ServiceStack.ServiceInterface.Cors.CorsFeature());
So this way ServiceStack responds with "200 OK" on every request with "OPTIONS" header, regardless of url, dto and service declarations.
来源:https://stackoverflow.com/questions/14903101/servicestack-returns-405-on-options-request