> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xbrod.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 上传文件

> 上传图片文件并获取地址。

```bash cURL theme={null}
curl -X POST 'https://upload.xbrod.com/v1/upload' \
  -H 'Authorization: Bearer <token>' \
  -F 'files=@/path/to/reference.png'
```

```python Python theme={null}
import requests

with open('/path/to/reference.png', 'rb') as image:
    response = requests.post('https://upload.xbrod.com/v1/upload',
        headers={'Authorization': 'Bearer <token>'}, files={'files': image})
print(response.json())
```

```javascript JavaScript theme={null}
import { openAsBlob } from 'node:fs';

const form = new FormData();
form.append('files', await openAsBlob('/path/to/reference.png'), 'reference.png');
const response = await fetch('https://upload.xbrod.com/v1/upload', {
  method: 'POST',
  headers: { Authorization: 'Bearer <token>' },
  body: form,
});
console.log(await response.json());
```

```go Go theme={null}
package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
    "path/filepath"
)

func main() {
    file, err := os.Open("/path/to/reference.png")
    if err != nil { panic(err) }
    defer file.Close()
    var body bytes.Buffer
    writer := multipart.NewWriter(&body)
    part, err := writer.CreateFormFile("files", filepath.Base(file.Name()))
    if err != nil { panic(err) }
    if _, err := io.Copy(part, file); err != nil { panic(err) }
    if err := writer.Close(); err != nil { panic(err) }
    req, err := http.NewRequest("POST", "https://upload.xbrod.com/v1/upload", &body)
    if err != nil { panic(err) }
    req.Header.Set("Authorization", "Bearer <token>")
    req.Header.Set("Content-Type", writer.FormDataContentType())
    resp, err := http.DefaultClient.Do(req)
    if err != nil { panic(err) }
    defer resp.Body.Close()
    result, err := io.ReadAll(resp.Body)
    if err != nil { panic(err) }
    fmt.Println(string(result))
}
```

```java Java theme={null}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;

public class Example {
    public static void main(String[] args) throws Exception {
        var file = Path.of("/path/to/reference.png");
        var boundary = "----xbrod-" + UUID.randomUUID();
        var header = ("--" + boundary + "\r\nContent-Disposition: form-data; name=\"files\"; filename=\"" +
            file.getFileName() + "\"\r\nContent-Type: image/png\r\n\r\n").getBytes(StandardCharsets.UTF_8);
        var footer = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8);
        var body = HttpRequest.BodyPublishers.ofByteArrays(List.of(header, Files.readAllBytes(file), footer));
        var request = HttpRequest.newBuilder(URI.create("https://upload.xbrod.com/v1/upload"))
            .header("Authorization", "Bearer <token>")
            .header("Content-Type", "multipart/form-data; boundary=" + boundary)
            .POST(body).build();
        var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
```

```php PHP theme={null}
<?php
$ch = curl_init('https://upload.xbrod.com/v1/upload');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer <token>'],
    CURLOPT_POSTFIELDS => ['files' => new CURLFile('/path/to/reference.png')],
    CURLOPT_RETURNTRANSFER => true,
]);
$result = curl_exec($ch);
if ($result === false) { throw new RuntimeException(curl_error($ch)); }
curl_close($ch);
echo $result;
```

```ruby Ruby theme={null}
require 'net/http'

uri = URI('https://upload.xbrod.com/v1/upload')
File.open('/path/to/reference.png', 'rb') do |image|
  request = Net::HTTP::Post.new(uri)
  request['Authorization'] = 'Bearer <token>'
  request.set_form([['files', image]], 'multipart/form-data')
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(request) }
  puts response.body
end
```

文件上传使用本项目创建的 API 密钥作为 Bearer Token。

## 请求示例

在运行 curl 的机器上指定本地文件路径；`@` 表示读取文件内容。多张图片可重复传入 `files` 字段：

```bash theme={null}
curl -X POST 'https://upload.xbrod.com/v1/upload' \
  -H 'Authorization: Bearer <本项目 API 密钥>' \
  -F 'files=@/path/to/reference.png'
```

```bash theme={null}
curl -X POST 'https://upload.xbrod.com/v1/upload' \
  -H 'Authorization: Bearer <本项目 API 密钥>' \
  -F 'files=@/path/to/first.png' \
  -F 'files=@/path/to/second.jpg'
```

上传服务返回 `status` 和 `files` 数组。请从对应文件的 `url` 读取地址，并检查其 `status`；批量上传时不要仅凭顶层状态判断每个文件是否成功。文件上传不支持传 `image_url`，若手头只有公网图片地址，请使用[图片地址上传](https://docs.xbrod.com/uploads/images.md)。


## OpenAPI

````yaml openapi-file-upload.yaml POST /v1/upload
openapi: 3.0.3
info:
  title: 文件上传服务
  version: 1.0.0
  description: 独立文件上传服务；该请求不发送到 ai.xbrod.com。
servers:
  - url: https://upload.xbrod.com
    description: 文件上传地址
security:
  - bearerAuth: []
paths:
  /v1/upload:
    post:
      summary: 上传文件
      description: 上传本地文件；可重复传入 files 字段上传多张图片。
      operationId: uploadFiles
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - files
              properties:
                files:
                  type: array
                  description: 本地图片文件；可重复提交 files 字段。
                  items:
                    type: string
                    format: binary
            encoding:
              files:
                style: form
                explode: true
      responses:
        '200':
          description: 上传结果；逐项检查 files 中的状态和地址。
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                  files:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                      properties:
                        index:
                          type: integer
                        status:
                          type: string
                        url:
                          type: string
                          format: uri
                        bytes:
                          type: integer
                          format: int64
                        content_type:
                          type: string
        '401':
          description: 密钥无效或已撤销。
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 本项目创建的 API 密钥。

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.