Skip to content

Ruby Web服务

Web服务是现代应用程序架构的重要组成部分,它们允许不同系统之间通过网络进行通信和数据交换。Ruby提供了多种创建和消费Web服务的方式,从简单的HTTP服务器到复杂的RESTful API。本章将详细介绍如何在Ruby中创建Web服务,包括使用内置库和流行的框架如Sinatra和Rails。

🎯 Web服务基础

什么是Web服务

Web服务是一种通过网络提供功能的软件系统,它使用标准化的协议(如HTTP、XML、JSON)进行通信。Web服务的主要特点包括:

  • 互操作性: 不同平台和语言的系统可以相互调用
  • 松耦合: 服务提供者和消费者之间依赖关系最小
  • 可重用性: 同一个服务可以被多个应用程序使用
  • 可发现性: 服务可以通过标准方式被发现和调用

Web服务类型

  1. SOAP Web服务: 基于XML的协议,使用WSDL描述服务
  2. RESTful Web服务: 基于HTTP协议,使用JSON/XML传输数据
  3. GraphQL: 现代API查询语言,允许客户端精确指定需要的数据

🌐 使用内置库创建Web服务

基本HTTP服务器

ruby
require 'webrick'

# 创建简单的HTTP服务器
class SimpleHTTPServer
  def initialize(port = 8080)
    @port = port
    @server = nil
  end
  
  def start
    # 配置服务器
    config = {
      Port: @port,
      DocumentRoot: './public'
    }
    
    @server = WEBrick::HTTPServer.new(config)
    
    # 定义路由处理器
    @server.mount_proc('/hello') do |req, res|
      res.body = 'Hello, World!'
      res['Content-Type'] = 'text/plain'
    end
    
    @server.mount_proc('/api/time') do |req, res|
      res.body = { 
        time: Time.now.to_s,
        timestamp: Time.now.to_i
      }.to_json
      res['Content-Type'] = 'application/json'
    end
    
    # 处理POST请求
    @server.mount_proc('/api/echo') do |req, res|
      res.body = {
        method: req.request_method,
        path: req.path,
        headers: req.header,
        body: req.body
      }.to_json
      res['Content-Type'] = 'application/json'
    end
    
    # 优雅关闭
    trap('INT') { @server.shutdown }
    
    puts "服务器启动,监听端口 #{@port}"
    @server.start
  end
end

# 启动服务器
# server = SimpleHTTPServer.new(8080)
# server.start

# 处理静态文件
class StaticFileHandler < WEBrick::HTTPServlet::AbstractServlet
  def do_GET(request, response)
    file_path = request.path == '/' ? '/index.html' : request.path
    full_path = File.join('./public', file_path)
    
    if File.exist?(full_path) && !File.directory?(full_path)
      response.body = File.read(full_path)
      response['Content-Type'] = get_content_type(full_path)
      response.status = 200
    else
      response.body = '<h1>404 Not Found</h1>'
      response['Content-Type'] = 'text/html'
      response.status = 404
    end
  end
  
  private
  
  def get_content_type(file_path)
    ext = File.extname(file_path).downcase
    case ext
    when '.html' then 'text/html'
    when '.css' then 'text/css'
    when '.js' then 'application/javascript'
    when '.json' then 'application/json'
    when '.png' then 'image/png'
    when '.jpg', '.jpeg' then 'image/jpeg'
    else 'text/plain'
    end
  end
end

# 使用静态文件处理器
# server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public')
# server.mount('/', StaticFileHandler)
# trap('INT') { server.shutdown }
# server.start

RESTful API服务器

ruby
require 'webrick'
require 'json'

# 简单的内存数据库
class InMemoryDB
  def initialize
    @data = {}
    @next_id = 1
  end
  
  def create(item)
    id = @next_id
    @next_id += 1
    @data[id] = item.merge('id' => id, 'created_at' => Time.now.to_i)
    @data[id]
  end
  
  def find(id)
    @data[id.to_i]
  end
  
  def all
    @data.values
  end
  
  def update(id, item)
    return nil unless @data[id.to_i]
    @data[id.to_i] = item.merge('id' => id.to_i, 'updated_at' => Time.now.to_i)
    @data[id.to_i]
  end
  
  def delete(id)
    @data.delete(id.to_i)
  end
end

# RESTful API处理器
class RESTAPIHandler < WEBrick::HTTPServlet::AbstractServlet
  def initialize(server, db)
    super(server)
    @db = db
  end
  
  def do_GET(request, response)
    case request.path
    when '/api/users'
      # 获取所有用户
      users = @db.all
      send_json_response(response, users, 200)
      
    when %r{/api/users/(\d+)}
      # 获取特定用户
      id = $1
      user = @db.find(id)
      if user
        send_json_response(response, user, 200)
      else
        send_error_response(response, '用户未找到', 404)
      end
      
    else
      send_error_response(response, '路径未找到', 404)
    end
  end
  
  def do_POST(request, response)
    case request.path
    when '/api/users'
      # 创建用户
      begin
        user_data = JSON.parse(request.body)
        user = @db.create(user_data)
        send_json_response(response, user, 201)
      rescue JSON::ParserError
        send_error_response(response, '无效的JSON格式', 400)
      end
      
    else
      send_error_response(response, '路径未找到', 404)
    end
  end
  
  def do_PUT(request, response)
    case request.path
    when %r{/api/users/(\d+)}
      # 更新用户
      id = $1
      begin
        user_data = JSON.parse(request.body)
        user = @db.update(id, user_data)
        if user
          send_json_response(response, user, 200)
        else
          send_error_response(response, '用户未找到', 404)
        end
      rescue JSON::ParserError
        send_error_response(response, '无效的JSON格式', 400)
      end
      
    else
      send_error_response(response, '路径未找到', 404)
    end
  end
  
  def do_DELETE(request, response)
    case request.path
    when %r{/api/users/(\d+)}
      # 删除用户
      id = $1
      user = @db.delete(id)
      if user
        send_json_response(response, { 'message' => '用户已删除' }, 200)
      else
        send_error_response(response, '用户未找到', 404)
      end
      
    else
      send_error_response(response, '路径未找到', 404)
    end
  end
  
  private
  
  def send_json_response(response, data, status)
    response.body = data.to_json
    response['Content-Type'] = 'application/json'
    response.status = status
  end
  
  def send_error_response(response, message, status)
    response.body = { 'error' => message }.to_json
    response['Content-Type'] = 'application/json'
    response.status = status
  end
end

# 启动RESTful API服务器
# db = InMemoryDB.new
# server = WEBrick::HTTPServer.new(Port: 8080)
# server.mount('/api', RESTAPIHandler, db)
# 
# # 添加示例数据
# db.create({ 'name' => '张三', 'email' => 'zhangsan@example.com' })
# db.create({ 'name' => '李四', 'email' => 'lisi@example.com' })
# 
# trap('INT') { server.shutdown }
# puts "RESTful API服务器启动,监听端口 8080"
# server.start

🎵 使用Sinatra创建Web服务

Sinatra基础

Sinatra是一个轻量级的Ruby Web框架,非常适合创建RESTful API和小型Web应用:

ruby
# 首先安装Sinatra
# gem install sinatra

require 'sinatra'
require 'json'

# 基本Sinatra应用
get '/' do
  'Hello, Sinatra!'
end

get '/hello/:name' do
  "Hello, #{params[:name]}!"
end

# JSON API
get '/api/time' do
  content_type :json
  {
    time: Time.now.to_s,
    timestamp: Time.now.to_i
  }.to_json
end

# POST请求处理
post '/api/users' do
  content_type :json
  
  begin
    user_data = JSON.parse(request.body.read)
    # 这里应该保存到数据库
    user_data['id'] = rand(1000)
    user_data['created_at'] = Time.now.to_i
    
    status 201
    user_data.to_json
  rescue JSON::ParserError
    status 400
    { error: '无效的JSON格式' }.to_json
  end
end

# 启动应用
# ruby app.rb

完整的Sinatra API示例

ruby
require 'sinatra'
require 'json'
require 'securerandom'

# 用户模型
class User
  attr_accessor :id, :name, :email, :created_at
  
  def initialize(name, email)
    @id = SecureRandom.uuid
    @name = name
    @email = email
    @created_at = Time.now
  end
  
  def to_hash
    {
      id: @id,
      name: @name,
      email: @email,
      created_at: @created_at
    }
  end
end

# 用户服务
class UserService
  def initialize
    @users = {}
  end
  
  def create(name, email)
    user = User.new(name, email)
    @users[user.id] = user
    user
  end
  
  def find(id)
    @users[id]
  end
  
  def all
    @users.values
  end
  
  def update(id, name, email)
    return nil unless @users[id]
    @users[id].name = name if name
    @users[id].email = email if email
    @users[id]
  end
  
  def delete(id)
    @users.delete(id)
  end
end

# 全局用户服务实例
USER_SERVICE = UserService.new

# 配置
set :bind, '0.0.0.0'
set :port, 4567

# 中间件
before do
  content_type :json
  @request_body = request.body.read
end

# 错误处理
error 404 do
  { error: '页面未找到' }.to_json
end

error 500 do
  { error: '服务器内部错误' }.to_json
end

# 路由

# 首页
get '/' do
  {
    message: '欢迎使用用户管理API',
    version: '1.0.0',
    endpoints: [
      'GET /api/users',
      'GET /api/users/:id',
      'POST /api/users',
      'PUT /api/users/:id',
      'DELETE /api/users/:id'
    ]
  }.to_json
end

# 获取所有用户
get '/api/users' do
  users = USER_SERVICE.all.map(&:to_hash)
  users.to_json
end

# 获取特定用户
get '/api/users/:id' do
  user = USER_SERVICE.find(params[:id])
  if user
    user.to_hash.to_json
  else
    status 404
    { error: '用户未找到' }.to_json
  end
end

# 创建用户
post '/api/users' do
  begin
    data = JSON.parse(@request_body)
    
    # 验证必需字段
    if data['name'].nil? || data['email'].nil?
      status 400
      { error: '姓名和邮箱是必需的' }.to_json
    else
      user = USER_SERVICE.create(data['name'], data['email'])
      status 201
      user.to_hash.to_json
    end
  rescue JSON::ParserError
    status 400
    { error: '无效的JSON格式' }.to_json
  end
end

# 更新用户
put '/api/users/:id' do
  begin
    user = USER_SERVICE.find(params[:id])
    if user
      data = JSON.parse(@request_body)
      updated_user = USER_SERVICE.update(params[:id], data['name'], data['email'])
      updated_user.to_hash.to_json
    else
      status 404
      { error: '用户未找到' }.to_json
    end
  rescue JSON::ParserError
    status 400
    { error: '无效的JSON格式' }.to_json
  end
end

# 删除用户
delete '/api/users/:id' do
  user = USER_SERVICE.find(params[:id])
  if user
    USER_SERVICE.delete(params[:id])
    { message: '用户已删除' }.to_json
  else
    status 404
    { error: '用户未找到' }.to_json
  end
end

# 启动应用
# ruby app.rb

🚀 使用Rails创建Web服务

Rails API模式

Rails 5+提供了API模式,专门用于创建Web服务:

bash
# 创建Rails API应用
# rails new my_api --api
# cd my_api
ruby
# app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true, uniqueness: true
  
  # 序列化为JSON时包含的字段
  def as_json(options = {})
    super(options.merge(only: [:id, :name, :email, :created_at, :updated_at]))
  end
end
ruby
# app/controllers/api/v1/users_controller.rb
class Api::V1::UsersController < ApplicationController
  before_action :set_user, only: [:show, :update, :destroy]
  
  # GET /api/v1/users
  def index
    @users = User.all
    render json: @users
  end
  
  # GET /api/v1/users/1
  def show
    render json: @user
  end
  
  # POST /api/v1/users
  def create
    @user = User.new(user_params)
    
    if @user.save
      render json: @user, status: :created
    else
      render json: { errors: @user.errors }, status: :unprocessable_entity
    end
  end
  
  # PUT /api/v1/users/1
  def update
    if @user.update(user_params)
      render json: @user
    else
      render json: { errors: @user.errors }, status: :unprocessable_entity
    end
  end
  
  # DELETE /api/v1/users/1
  def destroy
    @user.destroy
    head :no_content
  end
  
  private
  
  def set_user
    @user = User.find(params[:id])
  rescue ActiveRecord::RecordNotFound
    render json: { error: '用户未找到' }, status: :not_found
  end
  
  def user_params
    params.require(:user).permit(:name, :email)
  end
end
ruby
# config/routes.rb
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :users
    end
  end
end

🔌 Web服务客户端

使用Net::HTTP

ruby
require 'net/http'
require 'json'
require 'uri'

class WebServiceClient
  def initialize(base_url)
    @base_url = base_url
    @uri = URI.parse(base_url)
  end
  
  def get(path)
    uri = URI.join(@uri, path)
    response = Net::HTTP.get_response(uri)
    parse_response(response)
  end
  
  def post(path, data)
    uri = URI.join(@uri, path)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request.body = data.to_json
    
    response = http.request(request)
    parse_response(response)
  end
  
  def put(path, data)
    uri = URI.join(@uri, path)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    
    request = Net::HTTP::Put.new(uri)
    request['Content-Type'] = 'application/json'
    request.body = data.to_json
    
    response = http.request(request)
    parse_response(response)
  end
  
  def delete(path)
    uri = URI.join(@uri, path)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    
    request = Net::HTTP::Delete.new(uri)
    response = http.request(request)
    parse_response(response)
  end
  
  private
  
  def parse_response(response)
    case response
    when Net::HTTPSuccess
      JSON.parse(response.body) rescue response.body
    else
      {
        error: true,
        status: response.code,
        message: response.message,
        body: response.body
      }
    end
  end
end

# 使用示例
# client = WebServiceClient.new('http://localhost:8080')
# 
# # GET请求
# users = client.get('/api/users')
# puts "用户列表: #{users}"
# 
# # POST请求
# new_user = client.post('/api/users', { name: '王五', email: 'wangwu@example.com' })
# puts "创建用户: #{new_user}"

使用HTTParty

ruby
# 首先安装HTTParty
# gem install httparty

require 'httparty'

class HTTPartyClient
  include HTTParty
  base_uri 'http://localhost:8080'
  
  def self.get_users
    get('/api/users')
  end
  
  def self.get_user(id)
    get("/api/users/#{id}")
  end
  
  def self.create_user(user_data)
    post('/api/users', body: user_data.to_json, headers: { 'Content-Type' => 'application/json' })
  end
  
  def self.update_user(id, user_data)
    put("/api/users/#{id}", body: user_data.to_json, headers: { 'Content-Type' => 'application/json' })
  end
  
  def self.delete_user(id)
    delete("/api/users/#{id}")
  end
end

# 使用示例
# users = HTTPartyClient.get_users
# puts users

# new_user = HTTPartyClient.create_user({ name: '赵六', email: 'zhaoliu@example.com' })
# puts new_user

🎯 Web服务安全

身份验证

ruby
require 'sinatra'
require 'json'
require 'jwt'

# JWT密钥
JWT_SECRET = 'your_secret_key'

# 用户存储(实际应用中应该使用数据库)
USERS = {
  'admin' => 'password123',
  'user' => 'userpass456'
}

# 生成JWT令牌
def generate_token(username)
  payload = {
    username: username,
    exp: Time.now.to_i + 3600  # 1小时过期
  }
  JWT.encode(payload, JWT_SECRET, 'HS256')
end

# 验证JWT令牌
def verify_token(token)
  JWT.decode(token, JWT_SECRET, true, algorithm: 'HS256')
rescue JWT::DecodeError
  nil
end

# 身份验证中间件
def authenticate!
  token = request.env['HTTP_AUTHORIZATION']&.split(' ')&.last
  if token
    begin
      payload = verify_token(token)
      @current_user = payload[0]['username']
    rescue
      halt 401, { error: '无效的令牌' }.to_json
    end
  else
    halt 401, { error: '缺少认证令牌' }.to_json
  end
end

# 登录端点
post '/auth/login' do
  content_type :json
  
  begin
    data = JSON.parse(request.body.read)
    username = data['username']
    password = data['password']
    
    if USERS[username] == password
      token = generate_token(username)
      { token: token, username: username }.to_json
    else
      status 401
      { error: '用户名或密码错误' }.to_json
    end
  rescue JSON::ParserError
    status 400
    { error: '无效的JSON格式' }.to_json
  end
end

# 受保护的端点
get '/api/protected' do
  content_type :json
  authenticate!
  
  { message: "Hello, #{@current_user}!", protected_data: '这是受保护的数据' }.to_json
end

# 启动应用
# ruby app.rb

请求验证

ruby
require 'sinatra'
require 'json'

# 参数验证器
class ParameterValidator
  def self.validate_user_params(params)
    errors = []
    
    if params['name'].nil? || params['name'].strip.empty?
      errors << '姓名是必需的'
    end
    
    if params['email'].nil? || params['email'].strip.empty?
      errors << '邮箱是必需的'
    elsif !params['email'].match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i)
      errors << '邮箱格式不正确'
    end
    
    errors
  end
  
  def self.validate_pagination_params(params)
    errors = []
    
    page = params['page']&.to_i
    per_page = params['per_page']&.to_i
    
    if page && page < 1
      errors << '页码必须大于0'
    end
    
    if per_page && (per_page < 1 || per_page > 100)
      errors << '每页数量必须在1-100之间'
    end
    
    errors
  end
end

# 使用参数验证
post '/api/users' do
  content_type :json
  
  begin
    data = JSON.parse(request.body.read)
    errors = ParameterValidator.validate_user_params(data)
    
    if errors.empty?
      # 处理有效的数据
      { message: '用户创建成功', user: data }.to_json
    else
      status 400
      { errors: errors }.to_json
    end
  rescue JSON::ParserError
    status 400
    { error: '无效的JSON格式' }.to_json
  end
end

get '/api/users' do
  content_type :json
  
  errors = ParameterValidator.validate_pagination_params(params)
  
  if errors.empty?
    page = (params['page'] || 1).to_i
    per_page = (params['per_page'] || 10).to_i
    
    { 
      page: page,
      per_page: per_page,
      data: [],
      total: 0
    }.to_json
  else
    status 400
    { errors: errors }.to_json
  end
end

📊 Web服务测试

使用RSpec测试API

ruby
# Gemfile
# gem 'rspec'
# gem 'rack-test'

require 'rspec'
require 'rack/test'

# 假设这是我们的Sinatra应用
class MyApp < Sinatra::Base
  get '/api/hello' do
    content_type :json
    { message: 'Hello, World!' }.to_json
  end
  
  post '/api/users' do
    content_type :json
    begin
      data = JSON.parse(request.body.read)
      status 201
      { id: 1, name: data['name'] }.to_json
    rescue JSON::ParserError
      status 400
      { error: 'Invalid JSON' }.to_json
    end
  end
end

# 测试文件
RSpec.describe MyApp, type: :request do
  include Rack::Test::Methods
  
  def app
    MyApp
  end
  
  describe 'GET /api/hello' do
    it 'returns a hello message' do
      get '/api/hello'
      
      expect(last_response).to be_ok
      expect(last_response.content_type).to include('application/json')
      
      response_data = JSON.parse(last_response.body)
      expect(response_data['message']).to eq('Hello, World!')
    end
  end
  
  describe 'POST /api/users' do
    context 'with valid JSON' do
      it 'creates a user' do
        user_data = { name: '张三' }.to_json
        
        post '/api/users', user_data, 'CONTENT_TYPE' => 'application/json'
        
        expect(last_response.status).to eq(201)
        expect(last_response.content_type).to include('application/json')
        
        response_data = JSON.parse(last_response.body)
        expect(response_data['name']).to eq('张三')
        expect(response_data['id']).to be_present
      end
    end
    
    context 'with invalid JSON' do
      it 'returns an error' do
        post '/api/users', 'invalid json', 'CONTENT_TYPE' => 'application/json'
        
        expect(last_response.status).to eq(400)
        expect(last_response.content_type).to include('application/json')
        
        response_data = JSON.parse(last_response.body)
        expect(response_data['error']).to eq('Invalid JSON')
      end
    end
  end
end

性能测试

ruby
require 'benchmark'
require 'net/http'
require 'uri'

# 性能测试工具
class PerformanceTester
  def self.test_endpoint(url, requests = 100)
    uri = URI(url)
    
    time = Benchmark.measure do
      requests.times do
        Net::HTTP.get_response(uri)
      end
    end
    
    {
      total_requests: requests,
      total_time: time.real,
      requests_per_second: requests / time.real,
      average_response_time: (time.real / requests) * 1000  # 毫秒
    }
  end
  
  def self.test_concurrent_requests(url, requests = 100, concurrency = 10)
    uri = URI(url)
    threads = []
    
    time = Benchmark.measure do
      # 分批并发请求
      (requests / concurrency).times do
        concurrency.times do
          threads << Thread.new do
            Net::HTTP.get_response(uri)
          end
        end
        
        # 等待这批请求完成
        threads.each(&:join)
        threads.clear
      end
    end
    
    {
      total_requests: requests,
      concurrency: concurrency,
      total_time: time.real,
      requests_per_second: requests / time.real
    }
  end
end

# 使用示例
# result = PerformanceTester.test_endpoint('http://localhost:8080/api/hello', 1000)
# puts "性能测试结果:"
# puts "总请求数: #{result[:total_requests]}"
# puts "总时间: #{result[:total_time].round(2)}秒"
# puts "每秒请求数: #{result[:requests_per_second].round(2)}"
# puts "平均响应时间: #{result[:average_response_time].round(2)}毫秒"

🎯 Web服务最佳实践

1. 版本控制

ruby
require 'sinatra'

# API版本控制
class APIv1 < Sinatra::Base
  get '/users' do
    content_type :json
    { version: 'v1', users: [] }.to_json
  end
end

class APIv2 < Sinatra::Base
  get '/users' do
    content_type :json
    { version: 'v2', users: [], metadata: {} }.to_json
  end
end

# 主应用路由到不同版本
class MainApp < Sinatra::Base
  use APIv1, '/api/v1'
  use APIv2, '/api/v2'
  
  get '/' do
    'API网关'
  end
end

# 启动应用
# run MainApp

2. 错误处理和日志

ruby
require 'sinatra'
require 'logger'

# 配置日志
logger = Logger.new(STDOUT)
logger.level = Logger::INFO

# 全局错误处理
error do
  error = env['sinatra.error']
  logger.error "错误: #{error.message}\n#{error.backtrace.join("\n")}"
  
  content_type :json
  status 500
  { 
    error: '内部服务器错误',
    request_id: request.env['HTTP_X_REQUEST_ID']
  }.to_json
end

# 请求日志中间件
before do
  request.env['HTTP_X_REQUEST_ID'] = SecureRandom.uuid
  logger.info "请求开始: #{request.request_method} #{request.path} (ID: #{request.env['HTTP_X_REQUEST_ID']})"
end

after do
  logger.info "请求结束: #{request.request_method} #{request.path} - #{status} (ID: #{request.env['HTTP_X_REQUEST_ID']})"
end

get '/api/test' do
  content_type :json
  { message: '测试成功' }.to_json
end

3. 缓存策略

ruby
require 'sinatra'
require 'redis'

# Redis缓存客户端
class CacheClient
  def initialize
    @redis = Redis.new(host: 'localhost', port: 6379)
  rescue
    @redis = nil
  end
  
  def get(key)
    return nil unless @redis
    @redis.get(key)
  end
  
  def set(key, value, ttl = 3600)
    return unless @redis
    @redis.setex(key, ttl, value)
  end
  
  def delete(key)
    return unless @redis
    @redis.del(key)
  end
end

# 缓存中间件
CACHE = CacheClient.new

def cached_response(key, ttl = 3600)
  # 尝试从缓存获取
  cached = CACHE.get(key)
  if cached
    logger.info "缓存命中: #{key}"
    return cached
  end
  
  # 执行实际操作
  result = yield
  
  # 存储到缓存
  CACHE.set(key, result, ttl)
  logger.info "缓存存储: #{key}"
  
  result
end

get '/api/expensive-operation' do
  content_type :json
  
  result = cached_response("expensive:#{Time.now.to_i / 60}") do
    # 模拟耗时操作
    sleep(2)
    { 
      message: '耗时操作完成',
      timestamp: Time.now.to_i,
      data: (1..100).to_a.sample(10)
    }.to_json
  end
  
  result
end

📚 下一步学习

掌握了Ruby Web服务开发后,建议继续学习:

继续您的Ruby学习之旅吧!

本站内容仅供学习和研究使用。