个人感觉还是IDHTTP更底层一点,而且还支持XML,并且接收值可以是JSON,也可以不是,返回值也是一样。可以任意返回内容,包括返回类似于HTML的内容。
1、IdHTTPServer1CommandGet事件中增加,支持允许跨域请求头属性,即可允许跨域访问,AJAX需要。(据说CSND中关于代码的说明越多,给的推荐情况越好,也许吧)关于跨域这个问题,目前我只与AJAX进行交互的时候遇到过,也许其它地方也能遇到,在RESTSERVER中也涉及到跨域这个问题,而且AJAX提交的内容与DELPHI一般的提交方式读取有点小区别,但是下面这个代码还是很有用的。如果有兴趣的人,可以查询一下,具体下面每个都是有什么用。另外,在与一些验证、支付相关的接口时,经常需要在交互的过程中向HTML数据头写其它信息,这个也是需要注意,通过经常与其它接口交互时的数据要求方面的经验,在写SERVER端的时候,感觉到还是IDHTTP这种比较底层的东西更方便控制。其实用SOCKT也可以完成IDHTTP的功能,但那个能有10年以上没用了,以前的代码都找不到了。而且现在IDHTTP还是比较常用的,在网上的代码也比较多。
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Origin:*');
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Headers:*');
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Method:*');
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Credentials:true');
AResponseInfo.CustomHeaders.Add('Access-Control-Max-Age:3600');
AResponseInfo.ContentType := 'text/HTML;charset=utf-8';
2、首先记录本次接收到的数据,方便在后面按模块带入不同的函数。下面的代码参考一下吧,据说文本少了,代码多了,CSND给的推荐少,也许这和写代码的注解相同吧,毕竟写代码的注解与和文字表达能力有关系,如果注解写的不好,其实也是白写。就好像我下面的代码这么长,其实完成的功能并没有什么太大的作用,只不过就是把入口参数先记录下来,而且大部分在赋值的时候都是以指针的形式保存的,不会发生内存泄露的情况。这样也有好处,就好像写一个函数,个人建议在函数的入口参数将整个函数过程中需要的变量先赋值了,这样的话,在未来对函数功能进行修改的时候,可以在入口处对变量的内容进行修改,避免了如果函数内容过多之后,需要修改的地方太多的情况。其实我平时写代码就经常加注解,一般来说2年之内自己写的注解,自己是能看明白的。
recv_url := ARequestInfo.Document;
info_in.url := recv_url;
info_in.AContext := AContext;
info_in.ARequestInfo := ARequestInfo;
info_in.AResponseInfo := AResponseInfo;
info_in.result_info.v2_result_list := '';
info_in.json_str := '';
recvText := reset_recv_post(ARequestInfo);
if recvText = '' then
begin
post_recv_type := 'ajax';
recvText := ARequestInfo.Params.Text;
info_in.json_str := recvText;
end
else
begin
post_recv_type := '常规';
end;
Memo1.Lines.Add('访问域名:' + ARequestInfo.Host);
Memo1.Lines.Add('地址栏参数:' + Httpdecode(ARequestInfo.QueryParams));
Memo1.Lines.Add('接收到访问类型为:' + ARequestInfo.Command + ' 访问模块为:' + recv_url + ' 访问时间为:' + DateTimeToStr(Now()));
Memo1.Lines.Add('访问者IP:' + AContext.Connection.Socket.Binding.PeerIP);
Memo1.Lines.Add('接收POST来源:' + post_recv_type);
Memo1.Lines.Add(recvText);
//根据访问模块调用不同函数
if UpperCase(copy(recv_url, 1, 6)) = UpperCase('/face/') then
begin
//微信中间件模块
face_in(info_in);
end;
3、不同语言进行交互数据时的方式不是,所以需要进行区分,提交上来的参数在哪里。下面的代码是一个小函数,因为AJAX在提交数据的时候将提交内容写到了流中,这与习惯用DELPHI写提交代码的同学获取方式不同,当时也是测试出来的。不知道是不是AJAX全这样,还是说与我对接的人接交方式就是这样,但这不重要了,因为通过下面的函数与上面的代码就可以解决这个问题。如果只给DELPHI的客户端写SERVER的话,也可以忽略下面这个函数与方法。毕竟还能再快一点。
function reset_recv_post(ARequestInfo: TIdHTTPRequestInfo): string;
var
Stream: TStream;
Buf: TBytes;
temp_result: string;
begin
temp_result := '';
if ARequestInfo.Command = 'POST' then // post
begin
if (ARequestInfo.PostStream <> nil) and (ARequestInfo.PostStream.Size > 0) then
begin
Stream := ARequestInfo.PostStream;
SetLength(Buf, Stream.Size);
Stream.Position := 0;
Stream.Read(Buf, Stream.Size);
temp_result := TEncoding.UTF8.GetString(Buf);
end;
end;
result := temp_result;
end;
4、生成返回值。代码中返回的是JSON,在其它模块中生成的,在其它模块中生成JSON的纯字符串,这样便于管理内存泄露的情况。如果想返回XML的话,就得自己写了,其实也可以直接返回简单的字符串,比如直接返回一个1或者2,但个人感觉还是有一个统一的返回结构比较好,毕竟我们是写SERVER的话,可以把这套习惯保留下来。也可以形成个人风格,关于个人风格大家可以参考百度或者其它常用的接口,一般都是一个返回码,一个错误码,还有一个返回值,有的接口还回多返回一个通讯是否成功,将返回码分为通讯成功与执行成功,但我个人感觉好像没有什么用处。
AResponseInfo.ContentType := 'text/HTML;charset=utf-8';
result_json := tjsonobject.Create;
result_json.AddPair('result_code', info_in.result_info.result_code);
result_json.AddPair('result_msg', info_in.result_info.result_msg);
result_list := tjsonobject.Create;
result_list := TJSONObject.parsejsonvalue(tencoding.utf8.getbytes(info_in.result_info.result_list), 0) as TJSONObject;
result_json.AddPair('result_list', result_list);
AResponseInfo.ContentText := AnsiToUtf8(result_json.ToString);
//result_list.Free;
result_json.Free;
说明:
1、DELPHI的中关于JSON的内存泄露挺烦人的,用XE10自带的JSON单元,需要自己测试一下,否则总会有多余的内存。
2、适当的加TRY可以避免各种情况。
3、在接收完所有参数后,可以专门写一个分析函数。
4、IDHTTP速度还是挺快的,因为比较底层,所以很多代码需要自己写。比如需要自己解析JSON、根据访问地址与访问方式进入不同的模块。但好处就是比较随意。