有没有方法在单次HTML请求中添加一个过渡页面? 比如服务器单个请求接收到请求后,立刻返回一个页面,但是连接并不结束,真正最终返回时返回一个全新的页面?并不是通过AJAX等方式实现。希望知道单次HTML请求的这种过渡页面的手段。
jerkzhang
结论:有的。
很早以前,我最初以为是通过多次来实现的,AJAX的实现方式如下:
比如先返回一个过渡页面给你,然后AJAX的方式进行请求真正要到达的页面,AJAX请求有延迟,反正过渡页面不会感觉到,然后服务器进行处理,把真正返回的结果页面存储在缓存中成功后返回success,然后JS在前端控制页面跳转到结果页面,结果页面请求直接从缓存中拿即可。
后来搜了一下ChatGPT,如下所述:
在单次HTML请求中实现过渡页面的方法通常涉及使用服务器端的技术来处理请求,并在处理期间向客户端发送一个过渡页面,然后再发送最终的页面内容。以下是一种可能的方法:
使用服务器端渲染(Server-Side Rendering,SSR):
当服务器接收到HTML请求时,可以首先发送一个简单的过渡页面,其中包含加载动画或简短的提示信息。
同时,服务器端可以继续处理请求,生成最终页面的内容。
当最终页面准备就绪时,服务器将其发送给客户端,取代过渡页面。
使用异步处理或非阻塞IO:
服务器可以采用异步处理请求的方式,在处理期间不阻塞其他请求的接收和处理。
这样,在生成最终页面的同时,服务器也可以发送一个过渡页面给客户端,以保持连接的开放状态。
一旦最终页面准备就绪,服务器就会发送它,取代过渡页面。
利用HTTP分块传输(Chunked Transfer Encoding):
服务器可以使用分块传输编码来逐步发送响应内容,而不是等到全部内容准备就绪后再发送。
这样可以使客户端可以尽早收到部分页面内容,包括过渡页面,而不必等待整个页面准备完成。
以上方法都需要服务器端代码的支持和修改来实现。具体的实现方式取决于使用的服务器技术和编程语言。例如,Node.js 可以使用 Express 框架实现异步处理,而 PHP 可以通过输出缓冲区(output buffering)来实现分块传输。
golang的echo实现上述功能的示例如下:
package main import ( "fmt" "net/http" "time" "github.com/labstack/echo/v4" ) func main() { e := echo.New() // 定义过渡页面的处理器 e.GET("/", func(c echo.Context) error { // 发送过渡页面 c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8) c.Response().WriteHeader(http.StatusOK) fmt.Fprintf(c.Response(), "<html><body>Loading...</body></html>") c.Response().Flush() // 模拟后台处理任务 time.Sleep(3 * time.Second) // 发送最终页面 c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTMLCharsetUTF8) c.Response().WriteHeader(http.StatusOK) fmt.Fprintf(c.Response(), "<html><body><h1>Hello, World!</h1></body></html>") c.Response().Flush() return nil }) // 启动服务器 e.Start(":8080") }
使用python2的tornado 5.0.2版本实现示例如下:
import tornado.ioloop import tornado.web import time class MainHandler(tornado.web.RequestHandler): @tornado.gen.coroutine def get(self): # 发送过渡页面 self.write("<html><body>Loading...</body></html>") yield self.flush() # 模拟后台处理任务 yield self.background_task() # 发送最终页面 self.write("<html><body><h1>Hello, World!</h1></body></html>") yield self.flush() @tornado.gen.coroutine def background_task(self): # 模拟后台处理任务 yield tornado.gen.sleep(3) def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
使用python3的tornado实现如下:
import tornado.ioloop import tornado.web import time class MainHandler(tornado.web.RequestHandler): async def get(self): # 发送过渡页面 self.write("<html><body>Loading...</body></html>") await self.flush() # 模拟后台处理任务 await self.background_task() # 发送最终页面 self.write("<html><body><h1>Hello, World!</h1></body></html>") await self.flush() async def background_task(self): # 模拟后台处理任务 await tornado.ioloop.IOLoop.current().run_in_executor(None, lambda: time.sleep(3)) def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()