# 缘起

看到Delphi盒子论坛里面有人讨论WEB开发,提到 IntraWeb 和 UniGUI 控件。

这两个控件都是在使用 Delphi 写后端(服务器端)的代码时,在后端构造页面代码,让浏览器访问时可以看到页面。这种做法把前端代码和后端代码混在一起了,基本上是 C/S 开发的模式。当然,传统的 WEB 开发,不管是 ASP,JSP 还是 PHP,也都是类似的模式。只是 Delphi 的上述两种框架提供了页面的可视化开发,拖拉控件就能出现页面。

从程序架构来说,后端只负责数据,前端代码只负责页面显示,这样分开,架构上更清晰,代码也更容易维护。WEB 开发转了一大圈,终于转到前端页面彻底用 JS 代码来实现并且也【组件化】了,基本上转到了 N 多年前 Delphi 的开发模式上了。

于是我想试试,后端用 Delphi 来写服务器,输出数据给前端,前端用 JS 来从服务器获取数据,渲染页面。当然,前端渲染页面的框架很多,比如 VUE 等等。这里我仅仅做研究,是否最终会用到哪个前端框架,接下来再说。

# 第一个测试

首先使用 Delphi 创建一个 Stand alone 模式的 WebBroker 工程,运行起来,默认工作在8080端口上面,让浏览器去访问它,就能看到页面。这个工程的基本代码是:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  
  Response.Content :=
    '<html>' +
    '<head><title>Web Server Application</title></head>' +
    '<body>Web Server Application</body>' +
    '</html>';
end;

上述代码,就是当这个服务器收到一个 HTTP 请求的时候,返回一堆字符串给浏览器。这堆字符串刚好是一个标准的 HTML 页面的代码,于是浏览器就显示这个 HTML 页面的内容了。

运行这个 WebBroker 的程序,打开浏览器,地址栏输入:http://127.0.0.1:8080

然后就能看到浏览器网页显示上述代码里面的那串文字了。你当然可以试着改掉那行字,重新编译运行程序,然后用浏览器重新打开(刷新一下页面)就能看到你输入的文字。

WebBroker 就是这么简单。

### 但是,这是在后端创建 HTML 代码!

# 我们来试试前端

首先,从前端如何向后端获取数据(仅仅是数据,而不是 HTML 页面代码)做起。

网上一搜,这篇文章说得不错:

javaScript中ajax、axios总结 - 唯美(vmei) - 博客园 (cnblogs)

这篇文章里面,提到 3 种方法:

1. 直接使用原生的 JS 代码;

2. 使用 jQuery 这个 JS 库;

3. 使用 axios 这个 JS 库;

使用原生的 JS 代码,代码行数比较多。使用 jQuery 这个库,我以前做过,这次就不想测试了。而且现在流行的前端框架 VUE 等都开始使用 axios,那我就试试 axios 和 Delphi 如何搭配吧。

## 前端页面代码:

<head>
<script src="https://unpkg/axios/dist/axios.min.js"></script>
</head>

<body>
<p> 实现前端调用后端的 HTTP 请求的方法:<br>
https://wwwblogs/hgdzjp/p/9438893.html
</p>
<p id="demo22">aaa</p>

<script>

axios.get('http://127.0.0.1:8080')
    .then(function(response){
        //请求成功
		document.getElementById("demo22").innerHTML = response.data;
    }).catch(function(erroe){
        //请求失败
    });



</script>

</body>

</html>

把这个页面保存为一个硬盘上的本地文件 test.html,直接用浏览器打开它,最终的显示内容符合我的预期,说明这段代码工作正常。

### 代码解释

上述页面代码,第一个 P 里面的一行字,就是典型的页面 HTML 代码, 浏览器打开这个文件,那个 P 里面包含的两行文字就显示出来。这个是静态 HTML 代码。

第二个 P ,其 id 是 demo22,其页面内容是 aaa(其实没有内容也不影响页面代码执行,我加上 aaa 是为了当页面 JS 代码没执行时,页面上能够显示这个 aaa 让我知道 JS 代码没执行。)

页面里面的 <script> 里面的代码,调用 axios 访问我的 WebBroker 服务器,将服务器返回的字符串,显示到这个 id 为 demo22 的 P 里面。

回头我改掉服务器端代码,不输出 HTML 页面代码给浏览器,仅仅输出一行普通的字符串当作数据,代码如下:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  {
  Response.Content :=
    '<html>' +
    '<head><title>Web Server Application</title></head>' +
    '<body>Web Server Application</body>' +
    '</html>';

    }


  Response.Content := 'hello this is WebBroker';
end;

如果正常运行,页面上那个显示 aaa 的地方,就应该显示服务器端这里给出的数据:hello this is WebBroker

问题是,页面没有正确显示。打开浏览器的开发工具界面,发现错误提示:

from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

网上搜索,原来是跨域访问的权限问题。浏览器打开的是本地文件,但里面的代码访问了一个远程IP地址的服务器,浏览器认为是跨域了。

解决办法:服务器端的 http 响应头里面,加上一个允许跨域的字符串定义(也就是增加一个 http 头)。因此服务器端代码修改如下:

procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  {
  Response.Content :=
    '<html>' +
    '<head><title>Web Server Application</title></head>' +
    '<body>Web Server Application</body>' +
    '</html>';

    }

  Response.CustomHeaders.Values['Access-Control-Allow-Origin'] := '*';
  Response.Content := 'hello this is WebBroker';
end;

上述代码里面,给 Response 的头增加的一个头的值是星号,表示这个域随便跨,没任何限制。

重新编译运行这个 Delphi 程序(其实就是在 Delphi 里面点一下中断运行的方框按钮,再点一下开始运行的三角箭头按钮),再次刷新页面,哈哈,结果出来了。

# 进一步的讨论

如果上述服务器端的代码里面,我访问数据库,把获得的数据打包成 JSON 格式的字符串返回给客户端,则浏览器的 JS 就能拿到 JSON 格式的数据。至于这个数据如何显示到页面上,就需要其它的页面显示的 JS 代码了。接下来继续测试吧。

当然,Delphi 本身提供了 DataSnap 框架,这个框架可以直接输出 RESTful 的接口(其实就是 http 的请求,返回 JSON 数据),采用 DataSnap 框架,可能比直接使用 WebBroker 框架来得简单,这个是后话。使用 WebBroker 框架,使得我们更容易理解一个 http 请求,在服务器端是如何处理的,代码更为直观。

# 后继

这个博客系列,我会慢慢通过做实验的方法来增加功能。不过时间上不能保证。

更多推荐

基于 Delphi 的前后端分离:之一