Racket 编程
第 2 部分 · Web 开发

Web 服务器基础

Web 服务器基础

使用 Racket 的内置 Web 服务器框架构建 HTTP 服务。

启动最简单的服务器

Racket 自带了 web-server 库,无需额外安装:

#lang racket

(require web-server/servlet
         web-server/servlet-env)

;; 定义请求处理器
(define (start req)
  (response/xexpr
   `(html
     (head (title "Hello Racket Web"))
     (body
      (h1 "Hello, Web!")
      (p "这是我的第一个 Racket Web 应用。")))))

;; 启动服务器
(serve/servlet start
               #:launch-browser? #t
               #:port 8080
               #:servlet-path "/")

运行这段代码,Racket 会启动一个 Web 服务器并在浏览器中打开 http://localhost:8080

路由处理

使用 dispatch/servlet 实现 URL 路由:

#lang racket

(require web-server/servlet
         web-server/servlet-env
         web-server/dispatch)

;; 路由处理器
(define (home-page req)
  (response/xexpr
   `(html (head (title "首页"))
          (body (h1 "欢迎来到首页")))))

(define (about-page req)
  (response/xexpr
   `(html (head (title "关于"))
          (body (h1 "关于我们")))))

(define (user-page req username)
  (response/xexpr
   `(html (head (title ,(format "用户: ~a" username)))
          (body (h1 ,(format "你好, ~a!" username))))))

;; 定义路由
(define-values (dispatch url)
  (dispatch-rules
   [(("about")) about-page]
   [(("user") (string-arg)) user-page]
   [else home-page]))

;; 启动
(serve/servlet dispatch
               #:port 8080
               #:servlet-regexp #rx"")

处理 GET 请求参数

(require web-server/request)

(define (search-page req)
  (define binds (request-bindings/raw req))
  (define query (bindings-assq #"q" binds))
  
  (response/xexpr
   `(html
     (head (title "搜索结果"))
     (body
      (h1 "搜索")
      (p ,(if query
              (format "你搜索了: ~a" (bytes->string/utf-8 (binding:form-value query)))
              "请输入搜索关键词"))))))

处理 POST 请求

(define (handle-form req)
  (define binds (request-bindings/raw req))
  (define name (bindings-assq #"name" binds))
  (define email (bindings-assq #"email" binds))
  
  (response/xexpr
   `(html
     (head (title "表单提交结果"))
     (body
      (h1 "提交成功")
      (p ,(format "姓名: ~a" (bytes->string/utf-8 (binding:form-value name))))
      (p ,(format "邮箱: ~a" (bytes->string/utf-8 (binding:form-value email))))))))

JSON API

使用 json 库构建 RESTful API:

(require json)

(define (api-users req)
  (response/json
   #hasheq((users . (#hasheq((id . 1) (name . "Alice"))
                     #hasheq((id . 2) (name . "Bob")))))))

;; 辅助函数:返回 JSON 响应
(define (response/json data)
  (response/full
   200
   #"OK"
   (current-seconds)
   APPLICATION/JSON-MIME-TYPE
   '()
   (list (jsexpr->bytes data))))

静态文件服务

(require web-server/dispatchers/dispatch-static)

;; 配置静态文件目录
(define static-dispatcher
  (static-files-path "/path/to/static/files"))

部署

Racket Web 应用可以通过多种方式部署:

方式说明
独立运行racket app.rkt 直接启动
Docker打包为容器镜像
Systemd配置为系统服务
反向代理配合 Nginx 使用
;; 生产环境配置
(serve/servlet app
               #:port (string->number (or (getenv "PORT") "8080"))
               #:listen-ip #f
               #:servlet-regexp #rx"")