我们有一个RemObjects SDK HTTP服务器,它公开了一些服务和方法。是否可以通过URI调用方法,而不是像SOAP/JSON一样传递参数,例如可以通过URI传递RemObjects SDK参数吗?
http://www.mywebservice.com/servicename/methodname?param1=xxx¶m2=yyy
我们有一个RemObjects SDK HTTP服务器,它公开了一些服务和方法。是否可以通过URI调用方法,而不是像SOAP/JSON一样传递参数,例如可以通过URI传递RemObjects SDK参数吗?
http://www.mywebservice.com/servicename/methodname?param1=xxx¶m2=yyy
UPDATE
我已经写了一个服务器后代的改进版本,它将一个格式化的URI转换成一个JSON对象,由RO JSON消息处理程序处理。
默认的处理方法是忽略URI。
变化URIHandlingMethod
到urhJSON
接受URI是这样的:
http://www.mywebservice.com/json?{JSON OBJECT}
设置URIHandlingMethod
到urhParametersto
接受URI是这样的:
http://www.mywebservice.com/json/service/method?param1=xxx¶m2=yyy
下面的代码:
unit ROJSONURIIndyHTTPServer ;
interface
uses
SysUtils, Classes,
uROIndyHTTPServer,
IdURI, IdCustomHTTPServer;
type
TURIHandlingMethod = (
urhNone,
urhJSON,
urhParameters
);
TROJSONURIIndyHTTPServer = class(TROIndyHTTPServer)
private
FURIHandlingMethod: TURIHandlingMethod;
FJSONVersion: String;
function ConvertURIToJSON(const Document, Params: String): String;
function NextBlock(var Value: String; Delimiter: Char = '/'): String;
protected
procedure InternalServerCommandGet(AThread: TIdThreadClass; RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo); override;
public
constructor Create(AOwner: TComponent); override;
published
property URIHandlingMethod: TURIHandlingMethod read FURIHandlingMethod write FURIHandlingMethod;
property JSONVersion: String read FJSONVersion write FJSONVersion;
end;
implementation
{ TROJSONURIIndyHTTPServer }
constructor TROJSONURIIndyHTTPServer.Create(AOwner: TComponent);
begin
inherited;
FJSONVersion := '1.1';
end;
function TROJSONURIIndyHTTPServer.NextBlock(var Value: String; Delimiter: Char): String;
var
p: Integer;
begin
p := 1;
while (p <= length(Value)) and (Value[p] <> Delimiter) do
Inc(p);
if p = length(Value) then
Result := Value
else
Result := copy(Value, 1, p - 1);
Value := copy(Value, p + 1, MaxInt);
end;
function TROJSONURIIndyHTTPServer.ConvertURIToJSON(const Document, Params: String): String;
const
JSONObjectTemplate = '{"method":"%s.%s"%s,"version": "%s"}';
JSONParamTemplate = '"%s":"%s"';
JSONParamsTemplate = ',"params":{%s}';
var
CallService, CallMessage,
ParsedDocument, ParsedParams, JSONParams,
Param, ParamName, ParamValue: String;
i: Integer;
begin
Result := '';
ParsedDocument := Trim(Document);
// Remove the leading/
if (length(Document) > 0) and
(Document[1] = '/') then
NextBlock(ParsedDocument);
// Remove the message type
NextBlock(ParsedDocument);
// Extract the service
CallService := NextBlock(ParsedDocument);
// Exctract the service message (method)
CallMessage := NextBlock(ParsedDocument);
JSONParams := '';
ParsedParams := Params;
while ParsedParams <> '' do
begin
// Extract the parameter and value
Param := NextBlock(ParsedParams, '&');
// See RFC 1866 section 8.2.1. TP
Param := StringReplace(Param, '+', ' ', [rfReplaceAll]); {do not localize}
// Extract the parameter name
ParamName := NextBlock(Param, '=');
// Extract the parameter value
ParamValue := Param;
// Add a delimiter if required
if JSONParams <> '' then
JSONParams := JSONParams + ',';
// Build the JSON style parameter
JSONParams := JSONParams + format(JSONParamTemplate, [ParamName, ParamValue]);
end;
if JSONParams <> '' then
JSONParams := format(JSONParamsTemplate, [JSONParams]);
// Make sure we have values for all the object variables, then build the JSON object
if (CallService <> '') and
(CallMessage <> '') and
(FJSONVersion <> '') then
Result := format(JSONObjectTemplate, [CallService, CallMessage, JSONParams, JSONVersion]);
end;
procedure TROJSONURIIndyHTTPServer.InternalServerCommandGet(
AThread: TIdThreadClass; RequestInfo: TIdHTTPRequestInfo;
ResponseInfo: TIdHTTPResponseInfo);
begin
if FURIHandlingMethod in [urhJSON, urhParameters] then
begin
// Parse parameters into JSON if required
if FURIHandlingMethod = urhParameters then
RequestInfo.UnparsedParams := ConvertURIToJSON(RequestInfo.Document, RequestInfo.UnparsedParams);
// Decode the URI e.g. converts %20 to whitespace
RequestInfo.UnparsedParams := TIdURI.URLDecode(RequestInfo.UnparsedParams);
// This works around a bug in TROIndyHTTPServer. By adding a whitespace to the
// end of the QueryParams it forces the http server to process the parameters
RequestInfo.QueryParams := TIdURI.URLDecode(RequestInfo.QueryParams) + ' ';
end;
inherited;
end;
end.
原创回答
这是André的回答。
当前版本的RemObjects SDK的以下URI应该工作,但不会:
http://www.mywebservice.com/JSON?{"id":"{392543cf-f110-4ba3-95471b02ce5bd693}","method":"servicename.methodname","params":{"param1":"xxx","param2":"yyy"}}:
有2个原因:
我已经创建了一个解决这两个问题的ROIndyHTTPServer后代。代码如下:
unit FixedROIndyHTTPServer;
interface
uses
SysUtils, Classes,
uROIndyHTTPServer,
IdURI, IdCustomHTTPServer;
type
TFixedROIndyHTTPServer = class(TROIndyHTTPServer)
protected
procedure InternalServerCommandGet(AThread: TIdThreadClass; RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo); override;
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{ TFixedROIndyHTTPServer }
constructor TFixedROIndyHTTPServer.Create(AOwner: TComponent);
begin
inherited;
end;
procedure TFixedROIndyHTTPServer.InternalServerCommandGet(
AThread: TIdThreadClass; RequestInfo: TIdHTTPRequestInfo;
ResponseInfo: TIdHTTPResponseInfo);
begin
// This fixes 2 issues with TROIndyHTTPServer
// 1) It decodes the parameters e.g. converts %20 to whitespace
// 2) It adds a whitespace to the end of the QueryParams. This
// forces the http server to process the parameters.
RequestInfo.QueryParams := TIdURI.URLDecode(RequestInfo.QueryParams) + ' ';
RequestInfo.UnparsedParams := TIdURI.URLDecode(RequestInfo.UnparsedParams);
inherited;
end;
end.
这并不回答我的问题,但它是任何有类似问题的人的解决方法。
我仍然渴望听到RO SDK是否支持使用自定义URI。
我认为你仍然应该将它发布到connect.remobjects.com –
对于'urhParametersto';我认为这个答案应该得到接受勾号。 –
+ CosminPrund - 好的,会的。这是你的帖子,给了我这个想法:) – norgepaul
据我所知:不是。
只能使用JSON结构做一些REST调用的: http://www.mywebservice.com/JSON { “ID”: “{392543cf-f110-4ba3-95471b02ce5bd693}”, “方法”: “servicename.methodname”,“PARAMS “:{” 参数1 “:” XXX”, “参数2”: “YYY”}}:
BTW:DataAbstract(基于RO)有一个REST接口,但RO本身不... :(
这是一个关于norgepaul's解决方案,看起来不错,并返回JSON。它基于使用TROIndyHTTPServer
的后裔拦截HTTP请求的相同想法,但是这次我不仅修复了请求的参数,而且还创建了客户端未发送的“JSON”文章!
下面是我用默认的测试“VCL Standalon”服务器上执行代码:
TUriROIndyHTTPServer = class(TROIndyHTTPServer)
protected
procedure InternalServerCommandGet(AThread: TIdThreadClass; RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo); override;
end;
procedure TUriROIndyHTTPServer.InternalServerCommandGet(AThread: TIdThreadClass;RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
var A, B: Integer;
NewPost: AnsiString;
begin
if RequestInfo.Document = '/json/sum' then
begin
// Extract the parameters
A := StrToIntDef(RequestInfo.Params.Values['a'], 0);
B := StrToIntDef(RequestInfo.Params.Values['b'], 0);
NewPost := AnsiString(Format('{"version":"1.1","method":"NewService.Sum","params":{"A":"%d","B":"%d"}}', [A, B]));
// Prepare the (fake) post-stream
RequestInfo.PostStream.Free;
RequestInfo.PostStream := TMemoryStream.Create;
RequestInfo.PostStream.Write(NewPost[1], Length(NewPost));
RequestInfo.PostStream.Position := 0;
end
else if RequestInfo.Document = '/json/getservertime' then
begin
// Extract the parameters
NewPost := '{"version":"1.1","method":"NewService.GetServerTime"}';
// Prepare the (fake) post-stream
RequestInfo.PostStream.Free;
RequestInfo.PostStream := TMemoryStream.Create;
RequestInfo.PostStream.Write(NewPost[1], Length(NewPost));
RequestInfo.PostStream.Position := 0;
end;
inherited;
end;
有了这种代码的地方,我可以作出这样的请求:
http://localhost:8080/json/sum?a=1&b=2
返回(在浏览器!)
{"version":"1.1","result":"3"}
这:
个http://localhost:8080/json/getservertime
回报这个(当然,在写这篇文章的时间):
{"version":"1.1","result":"2013-02-01T19:24:24.827"}
结果(在浏览器或外部应用程序中)是纯JSON,因为它已被格式化为“JSON消息” RO的代码。
@ cosmin-尼斯的想法。这将是很好,如果它是通用的,并与任何服务/参数列表一起工作。它应该很容易实现。如果它能够工作的话,我明天就会去找它并在这里发布。 – norgepaul
@norgepaul,我正在研究使其通用。我是非常新的RO-SDK,我试图弄清楚最终如何分派服务。这些信息肯定在某处。我确信我们可以使用RODL阅读器直接从RODL中提取相同的信息。解决方案绝对有可能。 –
@ Cosmin - 为了保持简单我只是按照您已经在这里开始的方法。如果你有一个类似http:// webservice/json/service/method的URI?param1 = xxx&param2 = yyy只是解析出服务,方法和参数,然后创建一个JSON对象,例如{“version”:“1.1”,“method”:“service.method”,“params”:{“param1”:“xxx”,“param2”:“yyy”}} ...就是这样!如果你有时间去调查,肯定会有更优雅的方式来做到这一点:) – norgepaul
您可能会从供应商那里得到一个更直接的答案,在connect.remobjects.com上,并不是说这不是一个好的地方。 –
@ WarrenP-通常我会同意 - RemObjects有很棒的产品,但是他们的支持需要很长时间才能做出回应。我虽然这可能会更快发布在这里:) – norgepaul
@norgepaul - 如果他们曾经回应... – RBA