TRestRequest.Execute 当响应代码为 300 或更高时退出线程

TRestRequest.Execute exits thread when responses code is 300 or higher

我需要检查来自 RestResponse 的特定状态代码,但是 RestRequest.Execute 似乎在状态代码不是 200 时生成 EHTTPProtocolException

我确实看过文档,它说 The request execution does not raise HTTP protocol exceptions. To verify the response status, check the TCustomRESTResponse.StatusCode property.

我无法理解为什么 EHTTPProtocolException 会被引发。我怎样才能忽略它或压制它?我确实检查了它是否只是调试器,但即使在发布版本中以及 运行 独立时,代码也会在执行时停止。

我的代码如下:

procedure TdmWebsockets.GetRustMapURL(const Connection: TsgcWSConnection; const Data: string);
begin
  var jdata := TJSONObject.ParseJSONValue(Data);
  var restClient := TRESTClient.Create(Self);
  var restResponse := TRESTResponse.Create(Self);
  var restRequest := TRESTRequest.Create(Self);
  try
    var isStaging := jdata.GetValue<Boolean>('data.staging');
    var isBarren := jdata.GetValue<Boolean>('data.barren');
    var seed := jdata.GetValue<Int32>('data.seed');
    var size := jdata.GetValue<Int32>('data.size');

    restRequest.Client := restClient;
    restRequest.Response := restResponse;

    restClient.BaseURL := 'https://rustmaps.com/api/v2/maps/' + seed.ToString + '/' + size.ToString;

    restClient.RaiseExceptionOn500 := False;

    restRequest.AddParameter('staging', BoolToStr(isStaging, True));
    restRequest.AddParameter('barren', BoolToStr(isBarren, True));

    restRequest.Params.AddHeader('X-API-Key', 'REDACTED');

    restRequest.Method := TRESTRequestMethod.rmPOST;

    Writeln('before');
    restRequest.Execute;
    Writeln('after');

    var Writer: TJsonTextWriter;
    var StringWriter: TStringWriter;
    try
      StringWriter := TStringWriter.Create();
      Writer := TJsonTextWriter.Create(StringWriter);
      Writer.Formatting := TJsonFormatting.Indented;

      Writer.WriteStartObject;
      /////////////////////////////////////////////
      Writer.WritePropertyName('command');
      Writer.WriteValue(COMMAND_GETMAP);
      /////////////////////////////////////////////
      if restResponse.Status.SuccessOK_200 or restResponse.Status.ClientErrorDuplicate_409 then
      begin
        Writeln('200 ok');

        Writer.WritePropertyName('success');
        Writer.WriteValue(True);
      /////////////////////////////////////////////
        var mapID := restResponse.JSONValue.GetValue<string>('mapId');

        Writer.WritePropertyName('mapID');
        Writer.WriteValue(mapID);
      /////////////////////////////////////////////
      end
      else if restResponse.Status.ClientErrorBadRequest_400 then
      begin
        Writeln('400 ok');
      /////////////////////////////////////////////
        Writer.WritePropertyName('success');
        Writer.WriteValue(False);
      /////////////////////////////////////////////
        var reason := restResponse.JSONValue.GetValue<string>('reason');

        Writer.WritePropertyName('reason');
        Writer.WriteValue(reason);
      /////////////////////////////////////////////
      end;

      Writer.WriteEndObject;

      Writeln(StringWriter.ToString);

      Connection.WriteData(StringWriter.ToString);
    finally
      StringWriter.Free;
      Writer.Free;
    end;
  finally
    restRequest.Free;
    restResponse.Free;
    restClient.Free;
    jdata.Free;
  end;
end;

编辑: 当单击异常 window 上的“中断”按钮时,它会将我带到 Rest.HttpClient 中的 Execute 方法,尽管它没有被添加到使用中。步进显示它在 Rest.HttpClient 中执行,而不是在 Rest.Client.

中执行

当尝试使用 try .. except 时,我需要 Rest.HttpClient 来获取异常类型 EHTTPProtocolException。使用 try .. except 时它仍然会抛出异常。我知道调试器仍会捕获它,但代码永远不会在 try .. except 中运行,只会在异常抛出后停止。

IF 异常正在转义 TRestRequest.Execute() 到您的代码中,然后用 try..except 捕获它。 EHTTPProtocolException 有一个 ErrorCode 属性 你可以看看,如果需要的话。

A try..except 根本不会阻止引发异常。调试器仍会显示引发的异常,除非您将调试器配置为忽略它。但是您的代码将能够 捕获 异常并根据需要进行处理。如果调试器因异常而中断,只需按 IDE 上的“运行”按钮或键盘上的 F9 即可继续执行,并且异常将传递给代码中最近的匹配异常处理程序。

例如:

try
  restRequest.Execute;
except
  // swallow ALL exceptions...
end;

继续前进,无需更新 uses 子句 - 除非您希望代码忽略非 EHTTPProtocolException 异常并让它们向上传播调用堆栈(如您所愿) ,在这种情况下,您可以改用它:

uses
  ..., REST.HttpClient;

try
  restRequest.Execute;
except
  on E: Exception do begin
    if not (E is EHTTPProtocolException) then begin
      // DON'T swallow unknown non-HTTP errors...
      raise;
    end;
    // swallow HTTP errors and let subsequent code check the status...
  end;
end;

或:

uses
  ..., REST.HttpClient;

try
  restRequest.Execute;
except
  on E: EHTTPProtocolException do begin
    // swallow HTTP errors and let subsequent code check the status...
  end;
  on E: Exception do begin
    // DON'T swallow unknown non-HTTP errors...
    raise;
  end;
end;

或:

uses
  ..., REST.HttpClient;

try
  restRequest.Execute;
except
  on E: EHTTPProtocolException do;
  // swallow only HTTP errors and let subsequent code check the status...
end;

但是,IF 异常没有转义 TRestRequest.Execute() 到您的代码中,那么这个问题就没有实际意义了。异常将在 Execute() 内部处理,根本不需要在您的代码中使用 try..except。如果您不想在调试代码时看到异常,那么只需 configure the debugger to ignore EHTTPProtocolException 并继续。

我误解了问题是什么,我关注的是抛出的 HTTPException 而不是真正的问题。似乎因为我的应用程序是一个控制台应用程序,并且 sgcWebsockets 中的线程的 NotifyEvent 是 noSync,所以每次调用 TCustomRESTClient.HandleEvent 时线程都会退出。在这种情况下,它被调用并实际通过,因为 restRequest.SynchronizedEvents 默认设置为 true 但应该为 false。

所以解决方案就是简单地做:

restRequest.SynchronizedEvents := False;