response_type

User 69e88e27

发布于:2026-01-13

# response_type 标签使用指南

## 概述

`response_type` 标签用于设置模板的响应类型,告诉控制器应该以什么格式返回响应内容。当需要返回非 HTML 格式的响应(如 Turbo Stream、JSON、XML)时,通常需要配合 `{% layout none %}` 使用。

## 语法

```liquid
{% response_type "类型" %}
```

## 支持的响应类型

- `html` - HTML 格式(默认值)
- `turbo_stream` - Turbo Stream 格式,用于 Hotwire Turbo 的流式更新
- `json` - JSON 格式,用于 API 接口
- `xml` - XML 格式

## 使用示例

### 1. 返回 Turbo Stream 格式

Turbo Stream 用于实现无刷新的页面局部更新,常用于表单提交、动态内容更新等场景。

```liquid
{% response_type "turbo_stream" %}
{% layout none %}

<turbo-stream action="replace" target="content">
  <template>
    <div id="content">更新后的内容</div>
  </template>
</turbo-stream>
```

**Turbo Stream 操作类型**:

- `append` - 在目标元素内部末尾追加内容
- `prepend` - 在目标元素内部开头插入内容
- `replace` - 替换目标元素的整个内容
- `update` - 更新目标元素的 innerHTML
- `remove` - 移除目标元素
- `before` - 在目标元素之前插入内容
- `after` - 在目标元素之后插入内容

**多操作示例**:

```liquid
{% response_type "turbo_stream" %}
{% layout none %}

{%# 移除旧元素 %}
<turbo-stream action="remove" target="old-element"></turbo-stream>

{%# 更新内容区域 %}
<turbo-stream action="replace" target="content-area">
  <template>
    <div id="content-area">
      {% render 'updated_content', data: data %}
    </div>
  </template>
</turbo-stream>

{%# 追加新元素 %}
<turbo-stream action="append" target="list-container">
  <template>
    {% render 'list_item', item: new_item %}
  </template>
</turbo-stream>
```

### 2. 返回 JSON 格式

用于创建 API 接口端点,返回结构化数据。

```liquid
{% response_type "json" %}
{% layout none %}

{
  "status": "success",
  "message": "操作成功",
  "data": {
    "id": 123,
    "name": "示例"
  }
}
```

**动态 JSON 示例**:

```liquid
{% response_type "json" %}
{% layout none %}

{
  "articles": [
    {% for article in articles %}
      {
        "id": {{ article.id }},
        "title": {{ article.title | json }},
        "created_at": {{ article.created_at | date: "%Y-%m-%d" | json }}
      }{% unless forloop.last %},{% endunless %}
    {% endfor %}
  ]
}
```

### 3. 返回 XML 格式

用于返回 XML 格式的数据。

```liquid
{% response_type "xml" %}
{% layout none %}

<?xml version="1.0" encoding="UTF-8"?>
<response>
  <status>success</status>
  <message>数据已更新</message>
  <data>
    <item id="1">内容1</item>
    <item id="2">内容2</item>
  </data>
</response>
```

### 4. 使用默认 HTML 格式

如果不设置 `response_type`,或者设置为 `html`,模板会以 HTML 格式返回。

```liquid
{% response_type "html" %}
<!-- 或者不设置 response_type -->

<h1>页面标题</h1>
<p>页面内容</p>
```

## 实际应用场景

### 场景 1:Turbo Stream 表单提交

表单提交后,使用 Turbo Stream 更新页面内容,显示验证错误或成功消息。

```liquid
{% response_type "turbo_stream" %}
{% layout none %}

{%# 替换表单,显示验证错误 %}
<turbo-stream action="replace" target="comment-form">
  <template>
    {% render 'comment_form', comment: comment, errors: errors %}
  </template>
</turbo-stream>

{%# 如果成功,追加新评论 %}
{% if comment.persisted? %}
  <turbo-stream action="append" target="comments-list">
    <template>
      {% render 'comment', comment: comment %}
    </template>
  </turbo-stream>
{% endif %}
```

### 场景 2:API JSON 响应

在静态模板中创建 API 接口端点。

```liquid
{% response_type "json" %}
{% layout none %}

{
  "articles": [
    {% for article in articles %}
      {
        "id": {{ article.id }},
        "title": {{ article.title | json }},
        "excerpt": {{ article.excerpt | json }},
        "created_at": {{ article.created_at | date: "%Y-%m-%d" | json }}
      }{% unless forloop.last %},{% endunless %}
    {% endfor %}
  ],
  "total": {{ articles.size }}
}
```

### 场景 3:错误响应

结合 `response_status` 返回错误信息。

```liquid
{% response_status 422 %}
{% response_type "json" %}
{% layout none %}

{
  "status": "error",
  "message": "验证失败",
  "errors": {
    "email": ["邮箱格式不正确"],
    "password": ["密码长度至少8位"]
  }
}
```

## 注意事项

1. **类型验证**:只接受 `html`、`turbo_stream`、`json`、`xml` 四个值,其他值会被忽略,使用默认的 HTML 格式

2. **必须配合 layout none**:当使用非 HTML 格式时,通常需要配合 `{% layout none %}` 禁用布局,避免布局的 HTML 结构(如 `<html>`、`<head>`、`<body>` 等标签)污染响应内容

3. **优先级**:布局(layout)中设置的 `response_type` 会覆盖模板中的设置,因此建议在模板中设置响应类型,而不是在布局中

4. **标签顺序**:将 `response_type` 标签放在模板的最前面,确保在渲染过程中正确设置响应类型

5. **内容格式**:确保响应内容符合指定的格式要求(如有效的 JSON、XML 或 Turbo Stream),否则可能导致解析错误

## 常见错误

### 错误 1:忘记禁用布局

```liquid
{%# ❌ 错误示例 %}
{% response_type "json" %}
<!-- 没有设置 layout none -->

{
  "status": "success"
}
```

**问题**:响应会被布局的 HTML 结构包装,导致 JSON 解析失败。

**解决**:

```liquid
{%# ✅ 正确示例 %}
{% response_type "json" %}
{% layout none %}

{
  "status": "success"
}
```

### 错误 2:响应类型拼写错误

```liquid
{%# ❌ 错误示例 %}
{% response_type "turbo-stream" %}  <!-- 应该是 turbo_stream -->
```

**问题**:类型值不匹配,会被忽略,使用默认的 HTML 格式。

**解决**:

```liquid
{%# ✅ 正确示例 %}
{% response_type "turbo_stream" %}
```

### 错误 3:在布局中设置响应类型

```liquid
{%# ❌ 不推荐的做法 %}
{%# 在模板中 %}
{% response_type "json" %}
{% layout "custom" %}

<!-- 在 layout/custom.liquid 中又设置了 -->
{% response_type "html" %}
```

**问题**:布局中的设置会覆盖模板中的设置,可能导致意外的响应格式。

**建议**:响应类型应该在模板中设置,而不是在布局中。

## 最佳实践

1. **始终配合 layout none**:当使用非 HTML 响应类型时,始终配合 `{% layout none %}` 禁用布局

2. **标签顺序**:将 `response_type` 和 `layout` 标签放在模板的最前面

3. **类型验证**:确保响应类型值拼写正确,使用下划线而不是连字符(`turbo_stream` 而不是 `turbo-stream`)

4. **内容格式**:确保响应内容符合指定的格式要求(如有效的 JSON、XML 或 Turbo Stream)

5. **测试验证**:在浏览器开发者工具中检查响应的 Content-Type 和内容格式,确保符合预期

6. **错误处理**:对于 API 响应,结合 `response_status` 返回适当的状态码

## 总结

`response_type` 标签是控制模板响应格式的关键标签,支持 HTML、Turbo Stream、JSON、XML 四种格式。当使用非 HTML 格式时,必须配合 `{% layout none %}` 禁用布局,以确保响应内容的格式正确。正确使用此标签可以实现丰富的交互效果,如无刷新页面更新、API 接口、流式响应等。

提交反馈