一、前言
笔者之前文章对于Webapi接口做了简单介绍,说明其在软件开发过程中重要性等;基本来说除了传统C/S端,采用直连数据库模式,大部分产品研发都会使用到webapi,也就是存在中间层服务或者前后端分离的后端部分;
二、语言实现过程
1、delphi的httpserver
使用TIdHTTPServer实现http请求接收与返回;
代码实现
TIdHTTPServer的IdHTTPYbServerCommandGet方法实现
procedure TFrmain.IdHTTPYbServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
ADataJson, yboutstr: string;
aRequestContent: string;
begin
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Origin:*');
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Headers:*');
AResponseInfo.CustomHeaders.Add('Access-Control-Allow-Method:*');
if (ARequestInfo.PostStream <> nil) and (ARequestInfo.PostStream.Size > 0) then
begin
ARequestInfo.PostStream.Position := 0;
aRequestContent := StreamToString(ARequestInfo.PostStream);
end;
ARequestInfo.CharSet := 'UTF-8';
aRequestContent := TIdURI.URLDecode(aRequestContent); //中文解码
SaveToLog('log', '0.Post请求-->入参:', aRequestContent);
if SameText(ARequestInfo.Document, '/api/JmzybinterfaceService/Buisness') = True then
begin
if UpperCase(ARequestInfo.Command) = 'POST' then
begin
try
CoInitialize(nil); // 一定要加上此行代码
try
//1.判断入参是否XML
if CheckXml(aRequestContent) < 0 then
begin
ADataJson := GenerateXml(-1, '入参非XML格式', '');
end
else
begin
//2.发起交易处理
if YbBusiness(aRequestContent, yboutstr) < 0 then
ADataJson := GenerateXml(-1, yboutstr, '')
else
ADataJson := GenerateXml(0, '正常', yboutstr);
end;
except
on e: Exception do
begin
ADataJson := GenerateXml(-1, '调用异常:' + e.Message, '');
SaveToLog('Tranerror', '请求异常', e.Message);
end;
end;
AResponseInfo.ContentType := 'text/html; charset=GB2312';
AResponseInfo.CharSet := 'UTF-8'; //指定中文字符集
AResponseInfo.ContentText := ADataJson;
finally
CoUninitialize; // 一定要加上此行代码
end;
end;
end
else if SameText(ARequestInfo.Document, '/api/GETSFZXX') = True then
begin
AResponseInfo.ContentType := 'text/html; charset=GB2312';
AResponseInfo.CharSet := 'UTF-8'; //指定中文字符集
AResponseInfo.ContentText := '{"a":"123"}';
end
else
begin
//404
AResponseInfo.CharSet := 'UTF-8'; //指定中文字符集
AResponseInfo.ResponseNo := 404;
AResponseInfo.ContentText := GenerateXml(-1, '请采用POST请求方式', '');
end;
SaveToLog('Yblog', '0.Post请求-->出参:', AResponseInfo.ContentText);
end;
Ps:
1.AResponseInfo.CustomHeaders 响应头文件添加;
2.ARequestInfo.PostStream 请求流
3. 响应报文体:
AResponseInfo.ContentType := 'text/html; charset=GB2312';
AResponseInfo.CharSet := 'UTF-8'; //指定中文字符集
AResponseInfo.ContentText := ADataJson;
delphi的编码需要特别注意字符集问题;
2、Unigui的server
Unigui 框架由于自身就是服务端,客户端与服务端交互也是通过Http来实现;监听事件 HTTPCommand
代码实现
procedure TUniServerModule.UniGUIServerModuleHTTPCommand(ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; var Handled: Boolean);
var
filerespon: IHTTPResponse;
Stream: TMemoryStream;
var
http1: TNetHTTPClient;
decryptstr,path,pathdecode:string;
Params: TStringList;
begin
// path:=ARequestInfo.QueryParams.ToLower;
// 解决跨域问题;-提供文件名即可;url;
if SameText('/api/getfile/test', ARequestInfo.URI) and (ARequestInfo.Command = 'GET') then
begin
AResponseInfo.ResponseText:='ok';
AResponseInfo.ResponseNo := 200;
http1 := TNetHTTPClient.Create(Self);
http1.UserAgent := 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52)';
http1.Accept := '*/*';
http1.AcceptLanguage := 'zh-cn';
http1.SendTimeout := 120000;
http1.ConnectionTimeout := 30000;
http1.ResponseTimeout := 60000;
http1.ContentType := 'application/json;charset=utf-8';
http1.HandleRedirects := True;
try
Stream := TMemoryStream.Create;
filerespon := http1.Get('http://192.168.43.85:9904/api/Getpdf/Getdata?filename=HIP.pdf', Stream);
if filerespon.StatusCode = 200 then // 确认请求成功
begin
AResponseInfo.ContentType := 'application/pdf';
// AResponseInfo.ContentDisposition := 'attachment;filename=HIP.pdf'; //下载文件
AResponseInfo.ContentLength := Stream.Size;
AResponseInfo.ContentStream := Stream; // := Stream;
end;
finally
Stream:=nil;
http1.Free;
end;
Handled := true;
end //获取检查报告文件
else if SameText('/api/getfile/bg', ARequestInfo.URI) and (ARequestInfo.Command = 'GET') then
begin
// 多路径请求,需要把后面地址都带上处理,先去除
path := Geturlparam(ARequestInfo.QueryParams, 'httpfile');
//解密
SM4decrypt(Configinfo.appscrectkey,path,decryptstr);
// pathdecode := UTF8Decode(HttpDecode(path));
pathdecode:=decryptstr;// UTF8Decode(HttpDecode(decryptstr));
AResponseInfo.ResponseText:='ok';
AResponseInfo.ResponseNo := 200;
http1 := TNetHTTPClient.Create(Self);
http1.UserAgent := 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52)';
http1.Accept := '*/*';
http1.AcceptLanguage := 'zh-cn';
http1.SendTimeout := 120000;
http1.ConnectionTimeout := 30000;
http1.ResponseTimeout := 60000;
http1.ContentType := 'application/json;charset=utf-8';
http1.HandleRedirects := True;
try
Stream := TMemoryStream.Create;
filerespon := http1.Get(pathdecode, Stream);
if filerespon.StatusCode = 200 then // 确认请求成功
begin
AResponseInfo.ContentType := 'application/pdf';
// AResponseInfo.ContentDisposition := 'attachment;filename=HIP.pdf'; //下载文件
AResponseInfo.ContentLength := Stream.Size;
AResponseInfo.ContentStream := Stream; // := Stream;
end;
finally
Stream:=nil;
http1.Free;
end;
Handled := true;
end;
end;
Ps:AResponseInfo 响应消息类
AResponseInfo.ContentType := 'application/pdf';
AResponseInfo.ContentLength := Stream.Size;
AResponseInfo.ContentStream := Stream; // := Stream;
3、.net webapi
笔者为.NET 7.0,.net 实现Controller类方法即可监听相关请求;
请求路由
代码实现
[HttpPost]
public HttpResponseMessage Getjyml()
{
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
string Resultstr = string.Empty;
string logstr = string.Empty;
string Injson = string.Empty;
//1.定义请求头和返回体内容
Request_Smartip_client request = new Request_Smartip_client();
Respon_Smartip respon_Smartip = new Respon_Smartip();
try
{
using (var sr = new StreamReader(Request.Body, Encoding.UTF8))
{
Injson = sr.ReadToEndAsync().GetAwaiter().GetResult();
}
var authHeader = Request.Headers["Authorization"][0];
string token = string.Empty;
if (authHeader.StartsWith("Bearer "))
{
token = authHeader.Substring("Bearer ".Length);
}
//1.初始化处理
request = JsonConvert.DeserializeObject<Request_Smartip_client>(Injson);
Ybml_service mytoken = new Ybml_service();
int resultcode = mytoken.Getjyxmdata(0, _traceid, token, Injson, out string outlog, out string outlogstr, out Exception exception);
if (resultcode == -9)
{
Exceptionless_helper.Exceptionlessinfo(exception);
}
logstr = logstr + "\r\n" + outlogstr;
Resultstr = outlog;
}
catch (Exception ex)
{
Exceptionless_helper.Exceptionlessinfo(ex);
respon_Smartip.responcode = -9;
respon_Smartip.responmessage = "请求异常:" + ex.Message;
Resultstr = respon_Smartip.Error(_traceid, Injson);
logstr = logstr + "\r\n" + "-9.捕获异常:" + ex.Message;
}
logstr = logstr + "\r\n" + "出参:" + Resultstr;
//2.自研日志平台
LoglocalHelper.WriteLog(logstr);
httpResponseMessage.Content = new StringContent(Resultstr, Encoding.UTF8, "application/json");
return httpResponseMessage;
}
此处例子返回为HttpResponseMessage
4、java spring boot
笔者之前对于java不是太熟悉,大学虽然学的java,基本都已经忘干净了,由于这两年信息化信创的需求越来越强烈,目前正在后端转换为Java语言,对于后端来说各类语言来说只是语法略微不同,稍加学习也能满足基本需求;
代码实现
package com.example.demo.webapi; import org.omg.CORBA.PUBLIC_MEMBER; import org.springframework.web.bind.annotation.*; import com.alibaba.fastjson2.*; @RestController @RequestMapping(value = "/api/Helloworld") public class Helloworld { @RequestMapping(value={"/Say"},method =RequestMethod.GET) public String Say() { return "你好吗"; } @RequestMapping(value={"/Test"},method = RequestMethod.POST) @ResponseBody public String Test(@RequestBody String requeststr) { String instr=requeststr; JSONObject data = JSON.parseObject(instr); System.out.print(data.getString("a")); return instr; } }
通过相关注解完成请求方法、路由相关定义监听,基本原来类似
三、说明
基本来说任何一种编程语言(非前端)都支持webapi方式,也就是说都支持做后端webapi服务,不同语言由于其原理以及相关协议处理不同,效率在大并发下会存在部分差异,主流相关编程语言问题不大,笔者任务.net 有个好处,其内存回收机制比较好,不用担心内存泄漏问题;有其它语言优点欢迎大家补充;笔者后续计划把目前自研的微服务架构后端部分(.net)增加一套java语言支持;