How to convert my REST API Delphi project which uses MVCFramework to use standard RAD Studio components instead

huangapple go评论79阅读模式
英文:

How to convert my REST API Delphi project which uses MVCFramework to use standard RAD Studio components instead

问题

我开发了一个项目,这个项目是我们公司一位老程序员开始的。他使用了MVCFramework (https://github.com/danieleteti/delphimvcframework) 来连接一个门户。由于他的代码写得很复杂,我临时整理了一个工作函数,只是为了让你看到连接背后的逻辑:

function ConnectionTest_MinimumCodeJustForStackoverflowUsersToSeeHowItWorks: Boolean;
var
  FBaseURL, FAuthURL, FClientID, FClientSecret, FAccessToken: string;
  FSSLSocket: TIdSSLIOHandlerSocketOpenSSL;
  FRestClient: MVCFramework.RESTClient.TRESTClient;
  http: TIdHTTP;
  ParameterList: TStringList;
  ping: string;
begin
  Result := False;
  FBaseURL := 'https://www.the_portal_addresse.de';
  FAuthURL := 'https://auth.the_portal_addresse.de/auth/token';
  FClientID := 'Bla';
  FClientSecret := 'Bla';
  FSSLSocket := TIdSSLIOHandlerSocketOpenSSL.Create;
  FSSLSocket.SSLOptions.Method := sslvSSLv23;
  FRestClient := MVCFramework.RESTClient.TRESTClient.Create(FBaseURL, INTERNET_DEFAULT_HTTPS_PORT, FSSLSocket);
  FRestClient.ContentType('application/json');
  FRestClient.Accept('application/json');
  FAccessToken := '';
  http := TIdHTTP.Create(nil);
  ParameterList := TStringList.Create;
  try
    try
      http.HandleRedirects := False;
      http.IOHandler := FSSLSocket;
      http.Request.ContentType := CONTENTTYPE_APPLICATION_X_WWW_FORM_URLENCODED;
      http.Request.BasicAuthentication := False;
      ParameterList.Add('grant_type=client_credentials');
      ParameterList.Add('client_id=' + FClientID);
      ParameterList.Add('client_secret=' + FClientSecret);
      FAccessToken := http.Post(FAuthURL, ParameterList);
      FAccessToken := TJSONObject.ParseJSONValue(FAccessToken).GetValue<string>('access_token');
    except
      Exit;
    end;
    FRestClient.SetBearerToken(FAccessToken);
    ping := FRestClient.doGet(BasePath + '/system/ping', []).BodyAsString;
    if LowerCase(ping) <> 'pong' then
      Exit;
    Result := True;
  finally
    FreeAndNil(ParameterList);
    FreeAndNil(http);
    FreeAndNil(FSSLSocket);
    FreeAndNil(FRestClient);
  end;
end;

请注意,我不打算在我的项目中使用这段代码,但我想要进行更改。此外,我无法联系到这位程序员,因为他已经被解雇了!

这个函数在MVCFramework下工作,但我不能使用在REST.Client.TRESTClient中定义的TRESTClient组件,因为REST.Client.TRESTClient.CreateMVCFramework.RESTClient.TRESTClient.Create不同。

也许使用MVCFramework也是一个不错的主意,但我想知道为什么我的转换后的代码(不使用MVCFramework)不工作,而出现以下错误:

Error connecting with SSL.
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure.

我尝试过的是:

function ConnectionTest_MinimumCodeJustForStackoverflowUsersToSeeHowItWorks_2: Boolean;
var
  ...
  FRestClient: REST.Client.TRESTClient;
  ...
begin
  ...
  FBaseURL := 'https://www.the_portal_addresse.de:443';
  FAuthURL := 'https://auth.the_portal_addresse.de:443/auth/token';
  ...
  FRestClient := REST.Client.TRESTClient.Create(FBaseURL);
  ...
  FAccessToken := http.Post(FAuthURL, ParameterList); // 错误!
  ...
end;

我还尝试将TRest...组件放在一个窗体上,以及OAuth1AuthenticatorOAuth2Authenticator组件,但是我无法进一步操作,因为我不知道如何设置'grant_type=client_credentials'

如何将我的函数转换为使用REST.Client.TRESTClient而不是MVCFramework.RESTClient.TRestClient

英文:

I develop a project which an old programmer in our company has started. He has used MVCFramework (https://github.com/danieleteti/delphimvcframework) to connect to a portal. Because his code is written so complicated, I gathered it temporarily like this working function just for you to see the logic behind the connection:

function ConnectionTest_MinimumCodeJustForStackoverflowUsersToSeeHowItWorks: Boolean;
var
  FBaseURL, FAuthURL, FClientID, FClientSecret, FAccessToken: string;
  FSSLSocket: TIdSSLIOHandlerSocketOpenSSL;
  FRestClient: MVCFramework.RESTClient.TRESTClient;
  http: TIdHTTP;
  ParameterList: TStringList;
  ping: string;
begin
  Result := False;
  FBaseURL := &#39;https://www.the_portal_addresse.de&#39;;
  FAuthURL := &#39;https://auth.the_portal_addresse.de/auth/token&#39;;
  FClientID := &#39;Bla&#39;; 
  FClientSecret := &#39;Bla&#39;; 
  FSSLSocket := TIdSSLIOHandlerSocketOpenSSL.Create;
  FSSLSocket.SSLOptions.Method := sslvSSLv23;
  FRestClient := MVCFramework.RESTClient.TRESTClient.Create(FBaseURL, INTERNET_DEFAULT_HTTPS_PORT, FSSLSocket);
  FRestClient.ContentType(&#39;application/json&#39;);
  FRestClient.Accept(&#39;application/json&#39;);
  FAccessToken := &#39;&#39;;
  http := TIdHTTP.Create(nil);
  ParameterList := TStringList.Create;
  try
    try
      http.HandleRedirects := False;
      http.IOHandler := FSSLSocket;
      http.Request.ContentType := CONTENTTYPE_APPLICATION_X_WWW_FORM_URLENCODED;
      http.Request.BasicAuthentication := False;
      ParameterList.add(&#39;grant_type=client_credentials&#39;);
      ParameterList.add(&#39;client_id=&#39; + FClientID);
      ParameterList.add(&#39;client_secret=&#39; + FClientSecret);
      FAccessToken := http.Post(FAuthURL, ParameterList);
      FAccessToken := TJSonObject.ParseJSONValue(FAccessToken).GetValue&lt;string&gt;(&#39;access_token&#39;);
    except
	  Exit;
    end;
    FRestClient.SetBearerToken(FAccessToken);
    ping := FRestClient.doGet(BasePath + &#39;/system/ping&#39;, []).BodyAsString;
    if LowerCase(ping) &lt;&gt; &#39;pong&#39; then
      Exit;
    Result := True;
  finally
    FreeAndNil(ParameterList);
    FreeAndNil(http);
    FreeAndNil(TIdSSLIOHandlerSocketOpenSSL);
    FreeAndNil(FRestClient);
  end;
end;

Note that I'm not going to use this code in my project but I want to change it. Also I have no access to this programmer because he is fired!

This function is working with MVCFramework but I cannot use the TRESTClient component which is defined in REST.Client instead, because REST.Client.TRESTClient.Create differs from the MVCFramework.RESTClient.TRESTClient.Create.

Maybe it is a good idea that I use the MVCFramework as well but I want to learn why my converted code (without MVCFramework) does not work and I get this error:

Error connecting with SSL.
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure.

What I have tried is:

function ConnectionTest_MinimumCodeJustForStackoverflowUsersToSeeHowItWorks_2: Boolean;
var
  ...
  FRestClient: REST.Client.TRESTClient;
  ...
begin
  ...
  FBaseURL := &#39;https://www.the_portal_addresse.de:443&#39;;
  FAuthURL := &#39;https://auth.the_portal_addresse.de:443/auth/token&#39;;
  ...
  FRestClient := REST.Client.TRESTClient.Create(FBaseURL);
  ...
      FAccessToken := http.Post(FAuthURL, ParameterList); // ERROR!
  ...

I also tried placing the TRest... components on a form, and also OAuth1Authenticator and OAuth2Authenticator components, but I couldn't go further because I didn't know how should I set the &#39;grant_type=client_credentials&#39;.

How can I convert my function to work using REST.Client.TRESTClient instead of MVCFramework.RESTClient.TRestClient?

答案1

得分: 1

OMG!我发现了问题!原来问题并不是代码,而是由我们的IT管理员设置错误的系统设置引起的。我们使用了安装了Delphi的虚拟机,以及许多组件、证书、Windows设置和软件安装。在我们的大型主项目中,编译和运行需要大量时间,我最初编写了第一个函数,但在临时文件夹中修改了一个新项目中的函数。初衷是通过单独运行项目来加快测试速度。

经过多次尝试和详尽的研究(让我头疼不已),我终于找到了原因。似乎某些DLL文件,特别是“libeay32.dll”和“ssleay32.dll”必须与我的可执行文件位于同一目录下。这些DLL文件存在于我们主项目的文件夹中,这就是为什么原始函数能够正常工作,而我的更改不能。理想情况下,我们的IT管理员应该正确配置Delphi或Windows的环境路径设置,这将防止我遇到这个问题。

我认为让每个人都意识到这个问题很重要,这就是为什么我发布了这个答案。我要向所有参与者表示诚挚的感谢,特别是David Schwartz,他投入了大量时间。

英文:

OMG! I've discovered the problem! It turns out the issue was not with the code, but rather with incorrect system settings set by our IT administrator. We are using a virtual machine with Delphi installed, along with numerous components, certificates, Windows settings, and software installations. In our large main project, which takes a significant amount of time to compile and run, I initially wrote the first function, but modified function in a new project located in a temporary folder. The intention was to speed up testing by running the project separately.

After numerous attempts and exhaustive research (which gave me a headache), I finally identified the cause. It appears that certain DLL files, specifically "libeay32.dll" and "ssleay32.dll" must reside in the same directory as my executable file. These DLL files were present in the folders of our main project, which is why the original function worked while my changes did not. Ideally, our IT administrator should have correctly configured the environment path settings for Delphi or Windows, which would have prevented me from encountering this problem.

I believe it's important for everyone to be aware of this issue, which is why I posted this answer. I want to express my sincere gratitude to all the participants, particularly David Schwartz, who dedicated a significant amount of time.

答案2

得分: 0

你被组件名称所迷惑,忽略了更大的背景:MVC是一种特定的资源管理方法。它桥接了三种不同的东西:模型(Model)、视图(View)和控制器(Controller)。如果你想切换到不同的范式,那么你需要完全重写你的客户端。

我喜欢以一个包含我想要的不同部分的示例开始,然后更改各个端点以及它们的实现。

请记住,其中一部分在服务器上运行,一部分是客户端访问(远程)服务。不要被它们可能都在同一台机器上或分离它们会导致问题的事实所迷惑。

我很愿意为你指出一个示例,但在这里不允许发布链接,而且示例太长了,无法在回复中发布,因为涉及到多个不同的单元。

首先,与MVC库断开联系。不要尝试使用现有的东西。从头开始。只有一个TRESTClient组件,它设计用于与服务器通信。你似乎只关注客户端这一方面,所以我不确定服务器需要什么,但根据服务的要求,从客户端访问服务器可能会非常简单。

如果你展示一下你试图连接到的服务的示例(规范),那么我们可以建议访问它的代码。但试图从MVC转换到其他东西要比从头开始编写代码复杂得多。

英文:

You're getting confused by the component names and missing the bigger picture: MVC is a specific kind of approach to managing resources. It bridges three different things: Model, View, and Controller. If you want to switch to a different paradigm, then you're going to need to rewrite your Client entirely.

I like to start with an example that has the different parts that I want, and then change the individual endpoints and then their implementation.

Remember that part of this is running on a server and part is a client accessing that (remote) service. Don't get confused by the fact that they may both be on the same machine or it's going to break as soon as you separate them.

I'd love to point you to an example, but they don't like posting links here, and an example is way too long to post in a reply as there would be several different units involved.

First, cut ties with the MVC library. Don't try using what's there. Start over. There's only ONE TRESTClient component, and it's designed to talk to a Server. You seem to only be focusing on the Client side here, so I'm not sure what the Server is needing, but accessing the server from a client can be very simple depending on what the service requires.

If you show an example of the service you're trying to connect to (the specs) then we could suggest code to access it. But trying to do a "conversion" from MVC to something else is way more complicated than just coding something from scratch.

答案3

得分: 0

SSL问题需要先解决:

> FSSLSocket.SSLOptions.Method := sslvSSLv23;

当前客户端库不再默认启用此选项。
如果服务器仍需要此弱密码算法,请查看如何在新客户端中启用它。

英文:

SSL problem to solve first:

> FSSLSocket.SSLOptions.Method := sslvSSLv23;

This option is not enabled by default on the current client libraries any more.
If the server still needs this weak cipher, then check how to enable it in the new client.

huangapple
  • 本文由 发表于 2023年7月3日 22:14:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76605596.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定