2016-08-05 82 views
1

我们遇到了由AngularJS客户端访问的Datasnap REST(Delphi 10.1柏林)服务器的问题。我无法激活授权,因为Angular无法在Pragma标题中发送dssession,似乎是CORS的一个问题,因为浏览器是改变Header的标志(使用--disable-web-security启动Chrome,运行良好)。关于Delphi的Datasnap ISAPI模块的CORS问题

即使在同一台计算机上运行Angular和Datasnap进行测试(Angular在localhost:8080和Datasnap在localhost:8081),浏览器会检测到这些调用是跨源呼叫,而当Angular尝试发送dssession时,到达Datasnap。注意:我允许使用以下方式进行跨源呼叫:代码http://delphi.org/2015/04/cors-on-datasnap-rest-server/

将服务器作为StandAlone应用程序运行我可以在WebModuleBeforeDispatch事件中看到TWebRequest获取值为“Pragma”的Access-Control-Request-Headers而不是预期的Pragma标题,所以它看起来像浏览器正在发出一个CORS Options请求,而Datasnap没有回应它(它会通过“命令关闭或未分配”消息引发TDSServiceException)。

我已经为StandAlone应用程序解决了这个问题,通过URL传递dssession(它不干扰参数的正常传递,因为我只使用来自AngularJS的POST调用),然后拦截WebModuleBeforeDispatch事件上的请求并手动添加Pragma Header,其中包含从调用URL检索到的dssession。

procedure TWebModule1.WebModuleBeforeDispatch(Sender: TObject; Request: TWebRequest; 
               Response: TWebResponse; var Handled: Boolean); 
var Token: string; 
begin 
    Response.SetCustomHeader('Access-Control-Allow-Origin','*');  // Allow CORS calls 

    Token := TIdHTTPAppRequest(Request).Query;   // Set session on Pragma from the URL 
    if Copy(Token, 1, 10) = 'dssession=' then begin 
    TIdHTTPAppRequest(Request).GetRequestInfo.RawHeaders.AddValue('Pragma', Token); 
    end; 

    if FServerFunctionInvokerAction <> nil then 
    FServerFunctionInvokerAction.Enabled := AllowServerFunctionInvoker; 
end; 

它工作正常上独立的应用程序,但是当我重新编译我的代码作为一个ISAPI模块,将其部署到最终生产环境,它不添加dssession附注头的请求,可能是因为它没有得到通过URL传递的信息,但我无法确定原因,因为我无法让我的Delphi调试该ISAPI模块。

我遵循本教程:http://edn.embarcadero.com/article/40873,我可以正确设置运行我的ISAPI模块,但是当我将w3wp.exe进程附加到我的Delphi调试器时,它不会停止到任何断点(它们显示为禁用状态,因为就像代码是使用Release Build而不是Debug Build编译的),事实上,w3wp.exe进程似乎被冻结,并且在我将它从Delphi调试器中分离出来之前不会参与任何调用。

因此,如果您的浏览器将它们检测为跨源呼叫,则希望能够调试该模块,更重要的是将dssession传递给ISAPI模块。

非常感谢。

+0

服务器CORS支持包括预检处理?关于你提供的链接的最后两条评论建议不是 –

+0

我找不到有关它的任何文档,但的确,Datasnap似乎不支持预检处理:-((这就是为什么我试图避免它,不使用定制头文件Pragma并通过URL发送dssession) –

+0

我对Angular不太了解,但是如果它确实是所有客户端(javascript)文件,为什么不能从同一个IIS实例中都托管?可以选择使用虚拟目录。跨域检查不会触发。 –

回答

2

我终于找到了一个很好的解决方案来设置Datasnap来回答CORS请求,因为它应该回答它们。

当您的Datasnap在WebModule.Before派发事件上收到COR请求时,您只需回答允许发送自定义标题(Pragma),将Handled设置为True非常重要,因此Datasnap不会尝试管理即OPTION请求作为调用方法的普通请求。

procedure TWebModule1.WebModuleBeforeDispatch(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); 
begin 
    Response.SetCustomHeader('Access-Control-Allow-Origin','*');   

    if Trim(Request.GetFieldByName('Access-Control-Request-Headers')) <> '' then 
    begin 
    Response.SetCustomHeader('Access-Control-Allow-Headers', Request.GetFieldByName('Access-Control-Request-Headers'));   
    Handled := True; 
    end; 

    if FServerFunctionInvokerAction <> nil then 
    FServerFunctionInvokerAction.Enabled := AllowServerFunctionInvoker; 
end; 
+1

在我的环境中(Delphi XE2,简单的WebBroker ISAPI模块,带有mod_isapi的apache 2.4)我必须将Access-Control-Request-Headers更改为Access_Control_Request_Headers,因为在Delphi XE2中TISAPIRequest.GetFieldByName(...)使用HTTP_前缀而不是HEADER_。对于HTTP_和HEADER_请参阅https://msdn.microsoft.com/en-us/library/ms524602%28v=vs.90%29.aspx?f=255&MSPPError=-2147217396 – Chris