将Python转换为Delphi代码

6
下面是Python代码:
from urllib.request import Request, urlopen
import urllib
import json

#ID access to API
TOKEN = "{YOUR_API_TOKEN}" # e.g.: "f03c3c76cc853ee690b879909c9c6f2a"
url = "https://cloudpanel-api.1and1.com/v1"

def _setStatusServer(id, content):
  #Configure the request
  _command = url + "/servers/" + id + "/status/action"
  _method = 'PUT'
  request = Request(_command, data=content.encode(encoding='utf_8'), 
                    headers={'X-TOKEN':TOKEN, 'content-
                    type':'application/json'}, 
                    method=_method)

   #Try to get the response
   try:
     response = urlopen(request)
     content = response.read()
     return (content.decode())
  #Fetch error
  except urllib.error.URLError as e:
      return("Error " + str(e.code) + ":" + e.reason) 

  #PARAMETERS
  id = "{YOUR_SERVER_ID}" # e.g.: "5340033E7FBBC308BC329414A0DF3C20"
  action = "REBOOT"
  method = "SOFTWARE"

  data = json.dumps({'action':action, 'method':method})

  #REBOOT server
  print(_setStatusServer(id, data))

我已经将代码转换为Pascal格式。
function TWFServerSetState.ExecuteCommand(id, ip_id, Content: string): string;
var
  HTTP: TIdHTTP;
  Command: string;
  InputStream: TStringStream;
  ResponseStream: TStringStream;

  str: string;
begin
  Result := '';
  HTTP := TIdHTTP.Create();
  try
    HTTP.Request.ContentEncoding := 'UTF-8';
    HTTP.Request.CustomHeaders.AddValue('X-TOKEN', Token);
    HTTP.Request.CustomHeaders.AddValue('content-type', 'application/json');
    HTTP.Request.ContentType := 'application/json';
    Command := GetAddress + '/servers/' + id + '/status/action';

    str := '{"method": "' + Content + '", "action": "' + ip_id + '"}';
    str := TIdEncoderMIME.EncodeString(STR, IndyUTF8Encoding);
    InputStream := TStringStream.Create(str, TEncoding.UTF8);
    ResponseStream := TStringStream.Create('', TEncoding.UTF8, false);
    try
      HTTP.Put(Command, InputStream, ResponseStream);
      Result := ResponseStream.DataString;
    finally
      ResponseStream.Free;
      InputStream.Free;
    end;
  finally
    HTTP.Free;
  end;
end;

然而,Python代码的执行结果是正常的。Delphi代码的执行结果返回了:

"HTTP/1.1 406 Not Acceptable"

有任何建议在转换时出错的地方吗?

根据mjn的建议,我删除了Mime编码,并更改了两个代码中的测试url。来自httpbin服务器的Python代码请求为:

{'X-token': {token}, 'Content-type': 'application/json'}
{
  "args": {}, 
  "data": "{\"method\": \"SOFTWARE\", \"action\": \"REBOOT\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Connection": "close", 
    "Content-Length": "42", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "Python-urllib/3.4", 
    "X-Token": "token"
  }, 
  "json": {
    "action": "REBOOT", 
    "method": "SOFTWARE"
  }, 
  "origin": "24.135.167.155", 
  "url": "http://httpbin.org/put"
}

来自Delphi代码

{
  "args": {}, 
  "data": "{\"method\": \"SOFTWARE\", \"action\": \"REBOOT\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Connection": "close", 
    "Content-Length": "42", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "Mozilla/3.0 (compatible; Indy Library)", 
    "X-Token": "token"
  }, 
  "json": {
    "action": "REBOOT", 
    "method": "SOFTWARE"
  }, 
  "origin": "176.67.200.136", 
  "url": "http://httpbin.org/put"
}

感谢您的提前支持。 Bojan

1
看起来你需要添加一个Accept:头。 - H. de Jonge
2
进行一些调试。比较这两个请求。它们有什么不同之处? - David Heffernan
1
这似乎有点不太可信,你觉得呢? - David Heffernan
2
使用Fiddler2等工具捕获真实的HTTP请求和响应,然后进行比较。 - mjn
2
想一想。如果请求是相同的,服务器将会做出相同的响应。这就是计算机的工作原理。我认为你还没有检查请求并且不知道如何调试它。 - David Heffernan
显示剩余10条评论
1个回答

3

您的Delphi代码没有像Python代码一样发送JSON数据。您的代码存在几个逻辑和编码错误。

正确的代码应该看起来更像这样:

function TWFServerSetState.ExecuteCommand(const ServerID, Action, Method: string): string;
var
  HTTP: TIdHTTP;
  Url: string;
  InputStream: TStringStream;
  str: string;
begin
  Result := '';
  HTTP := TIdHTTP.Create;
  try
    HTTP.Request.CustomHeaders.AddValue('X-TOKEN', Token);
    HTTP.Request.ContentType := 'application/json';
    Url := GetAddress + '/servers/' + ServerID + '/status/action';
    str := '{"method": "' + Method + '", "action": "' + Action + '"}';
    InputStream := TStringStream.Create(str, TEncoding.UTF8);
    try
      try
        Result := HTTP.Put(Url, InputStream);
      except
        on e: EIdHTTPProtocolException do
          Result := 'Error ' + IntToStr(e.ErrorCode) + ':' + e.Message;
      end;
    finally
      InputStream.Free;
    end;
  finally
    HTTP.Free;
  end;
end;

然后您可以这样调用它:
var
  id, action, method: string;
begin
  id := '{YOUR_SERVER_ID}'; // e.g.: "5340033E7FBBC308BC329414A0DF3C20"
  action := 'REBOOT';
  method := 'SOFTWARE';
  ExecuteCommand(id, action, method);
end;

谢谢你的回答。我已经以不同的参数名称编写了这个类,因为它是子类之一,它们都有不同的参数名称。真正的问题只在于 HTTP.Request.CustomHeaders.AddValue('content-type', 'application/json'); HTTP.Request.ContentType := 'application/json'; 因为服务器看到的是'application/json','application/json',并且无法接受此ContentType。httpbin.org/put仅编写了ContentType ='application/json'一次,但实际服务器并没有这样看待它。其他都是“正确的”。 - bojan gavrilovic
2
@bojangavrilovic 嗯,还有你在 Python 代码中没有进行 base64 编码 JSON 数据,以及你将“Content-Encoding”头设置为无效值。这些都导致了一个非常格式错误的请求。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接