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

# 上传大型媒体文件

> 对于大于 10 MB 的文件上传,获取一个预签名 URL 以上传文件

export const HeaderAPI = ({noProfileKey, profileKeyRequired}) => <>
    <ParamField header="Authorization" type="string" required>
      <a href="/apis/overview#authorization">API Key</a> of the Primary Profile.
      <br />
      <br />
      Format: <code>Authorization: Bearer API_KEY</code>
    </ParamField>
    {!noProfileKey && (profileKeyRequired ? <ParamField header="Profile-Key" type="string" required>
          <a href="/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField> : <ParamField header="Profile-Key" type="string">
          <a href="/apis/overview#profile-key-format">Profile Key</a> of a User Profile.
          <br />
          <br />
          Format: <code>Profile-Key: PROFILE_KEY</code>
        </ParamField>)}
  </>;

export const PlansAvailable = ({plans = [], maxPackRequired}) => {
  let displayPlans = plans;
  if (plans && plans.length === 1) {
    const lowerCasePlan = plans[0].toLowerCase();
    if (lowerCasePlan === "business") {
      displayPlans = ["Launch", "Business", "Enterprise"];
    } else if (lowerCasePlan === "premium") {
      displayPlans = ["Premium", "Launch", "Business", "Enterprise"];
    }
  }
  return <Note>
Available on {displayPlans.length === 1 ? "the " : ""}
{displayPlans.join(", ").replace(/\b\w/g, l => l.toUpperCase())}{" "}
{displayPlans.length > 1 ? "plans" : "plan"}.

{maxPackRequired && <span onClick={() => window.open('https://www.ayrshare.com/docs/additional/maxpack', '_self')} className="flex items-center mt-2 cursor-pointer">
 <span className="px-1.5 py-0.5 rounded text-sm" style={{
    backgroundColor: '#C264B6',
    color: 'white',
    fontSize: '12px'
  }}>
   Max Pack required
 </span>
</span>}
</Note>;
};

<PlansAvailable plans={["premium"]} maxPackRequired={false} />

对于大于 10 MB 的文件上传,请获取一个预签名 URL 来上传文件。

<ul class="custom-bullets">
  <li>最大文件上传大小为 5 GB。</li>
  <li>上传预签名 URL 生成后有效期为 30 分钟。</li>

  <li>
    Access URL 在上传后可用 30 天。所有已发布的帖子在社交网络端不会受到影响。超过该时间的定时帖子会在发布时报错。
  </li>
</ul>

<Tip>如果你的媒体已经可以通过外部 URL 访问(例如 S3 存储桶),可以跳过将文件上传到 Ayrshare 的步骤。只需在 POST 到 `/post` 端点时将外部可访问的 URL 放入 `mediaURLs` 请求体参数中,你的文件就会被自动上传。</Tip>

## Header Parameters

<HeaderAPI noProfileKey={true} />

## Query Parameters

<ParamField query="fileName" type="string">
  如果没有提供 contentType,则必须提供带扩展名的完整文件名。

  要上传的文件名称。必须包含扩展名,例如 .png、.jpg、.mov、.mp4 等。
</ParamField>

<ParamField query="contentType" type="string">
  要上传的媒体的 content-type。有效格式包括:`mp4`、`mov`、`png`、`jpg` 或 `jpeg`。

  例如,如果文件是 Quicktime .mov 文件,则 contentType 应为 `mov`。

  如果未提供,将使用 application/octet-stream。
</ParamField>

<RequestExample>
  ```bash cURL theme={"system"}
  curl \
  -H "Authorization: Bearer [API Key]" \
  -X GET https://api.ayrshare.com/api/media/uploadUrl?fileName=test.mov&contentType=mov
  ```

  ```javascript JavaScript theme={"system"}
  const API_KEY = "Your API Key";

  fetch("https://api.ayrshare.com/api/media/uploadUrl?fileName=test.mov&contentType=mov", {
        method: "GET",
        headers: {
          "Authorization": `Bearer ${API_KEY}`
        }
      })
        .then((res) => res.json())
        .then((json) => console.log(json))
        .catch(console.error);
  ```

  ```python Python theme={"system"}
  import requests

  headers = {'Authorization': 'Bearer [API_KEY]'}

  r = requests.get('https://api.ayrshare.com/api/media/uploadUrl?fileName=test.mov&contentType=mov', headers=headers)

  print(r.json())
  ```

  ```php PHP theme={"system"}
  <?php
  require 'vendor/autoload.php';    // Composer auto-loader using Guzzle. See .../guzzlephp.org/en/stable/overview.html

  $client = new GuzzleHttp\Client();
  $res = $client->request(
      'GET',
      'https://api.ayrshare.com/api/media/uploadUrl?fileName=test.mov&contentType=mov',
      [
          'headers' => [
              'Content-Type'      => 'application/json',
              'Authorization'     => 'Bearer API_KEY'
          ]
      ]
  );

  echo json_encode(json_decode($res->getBody()), JSON_PRETTY_PRINT);
  ```

  ```csharp C# theme={"system"}
  using System;
  using System.Net.Http;
  using System.Threading.Tasks;
  using System.Web;

  namespace MediaUploadUrlGETRequest_csharp
  {
      class MediaUploadUrl
      {
          static async Task Main(string[] args)
          {
              string API_KEY = "API_KEY";
              string baseUrl = "https://api.ayrshare.com/api/media/uploadUrl";

              // Build URL with query parameters
              var uriBuilder = new UriBuilder(baseUrl);
              var query = HttpUtility.ParseQueryString(string.Empty);
              query["fileName"] = "test.mov";
              query["contentType"] = "mov";
              uriBuilder.Query = query.ToString();

              using (var client = new HttpClient())
              {
                  client.DefaultRequestHeaders.Add("Authorization", "Bearer " + API_KEY);

                  try
                  {
                      HttpResponseMessage response = await client.GetAsync(uriBuilder.Uri);
                      response.EnsureSuccessStatusCode();
                      string responseBody = await response.Content.ReadAsStringAsync();
                      Console.WriteLine(responseBody);
                  }
                  catch (HttpRequestException e)
                  {
                      Console.WriteLine($"Error: {e.Message}");
                  }
              }
          }
      }
  }
  ```
</RequestExample>

## 响应详情

<ul class="custom-bullets">
  <li>`accessUrl` 是上传后用于访问媒体文件的 URL。</li>

  <li>
    `contentType` 是为待上传媒体设置的 content-type。上传媒体时,请在 *Content-Type* 头中使用它。
  </li>

  <li>`uploadUrl` 是用于 *PUT* 媒体文件的 URL。请参见下文。</li>
</ul>

### 其他端点示例

上传大文件的流程:

<ul class="custom-bullets">
  <li>
    通过 `/media/uploadUrl` 端点获取 `uploadURL` 和 `accessURL`。请参见上文。
  </li>

  <li>使用 *PUT* 方法上传文件,并将 *Content-Type* 设置为返回的 `contentType`。</li>
  <li>使用 `--upload-file` 配合媒体文件和 `uploadUrl` 上传媒体。</li>
  <li>上传成功时,将返回 `200` 响应。</li>

  <li>
    上传媒体文件后,在 POST 到 `/post` 端点时将 `accessUrl` 放入 `mediaUrls` 请求体参数中。
  </li>

  <li>
    **预签名上传 URL 只能上传一次**。如果发送了错误的文件,你必须创建一个新的上传 URL。文件上传失败时不会产生错误响应。请参见下文的[验证 URL 是否存在](/apis/media/verify-media-url)。
  </li>
</ul>

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X PUT \
  -H 'Content-Type: video/mp4' \
  --upload-file LOCAL_FILE_PATH uploadUrl
  ```

  ```javascript JavaScript theme={"system"}
  const fs = require("fs").promises;
  const uploadFileToSignedUrl = async (signedUrl, filePath) => {
      try {
        const fileBuffer = await fs.readFile(filePath);
        const response = await fetch(signedUrl, {
          method: "PUT",
          body: fileBuffer,
          headers: {
            "Content-Type": "video/mp4"
          }
        });

        if (response.ok) {
          console.log("File upload successful:", response.status);
        } else {
          console.error("File upload failed:", response.status);
        }
      } catch (error) {
        console.error("Error uploading file:", error);
      }
  };

  // Use the signed URL generated from the previous step
  const signedUrl = "SIGNED_URL";
  const filePath = "LOCAL_FILE_PATH";

  uploadFileToSignedUrl(signedUrl, filePath);
  ```

  ```python Python theme={"system"}
  import requests

  def upload_file_to_signed_url(signed_url, file_path):
      try:
          with open(file_path, 'rb') as file:
              response = requests.put(signed_url, data=file, headers={'Content-Type': 'video/mp4'})

          if response.ok:
              print("File upload successful:", response.status_code)
          else:
              print("File upload failed:", response.status_code)
      except Exception as error:
          print("Error uploading file:", error)

  # Use the signed URL generated from the previous step
  signed_url = "SIGNED_URL"
  file_path = "LOCAL_FILE_PATH"

  upload_file_to_signed_url(signed_url, file_path)
  ```

  ```php PHP theme={"system"}
  <?php

  function uploadFileToSignedUrl($signedUrl, $filePath) {
      try {
          $fileHandle = fopen($filePath, 'rb');
          if ($fileHandle === false) {
              throw new Exception('Cannot open the file');
          }

          $ch = curl_init($signedUrl);

          curl_setopt($ch, CURLOPT_PUT, true);
          curl_setopt($ch, CURLOPT_INFILE, $fileHandle);
          curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
          curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: video/mp4'));
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

          $response = curl_exec($ch);
          $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

          if ($httpCode == 200) {
              echo "File upload successful: " . $httpCode;
          } else {
              echo "File upload failed: " . $httpCode;
          }

          fclose($fileHandle);
          curl_close($ch);
      } catch (Exception $e) {
          echo "Error uploading file: " . $e->getMessage();
      }
  }

  // Use the signed URL generated from the previous step
  $signedUrl = "SIGNED_URL";
  $filePath = "LOCAL_FILE_PATH";

  uploadFileToSignedUrl($signedUrl, $filePath);
  ?>

  ```

  ```csharp C# theme={"system"}
  using System;
  using System.Net.Http;
  using System.IO;
  using System.Threading.Tasks;

  class Program
  {
      static async Task Main(string[] args)
      {
          string signedUrl = "SIGNED_URL"; // Replace with your signed URL
          string filePath = "LOCAL_FILE_PATH"; // Replace with your file path

          try
          {
              await UploadFileToSignedUrl(signedUrl, filePath);
          }
          catch (Exception ex)
          {
              Console.WriteLine("Error uploading file: " + ex.Message);
          }
      }

      static async Task UploadFileToSignedUrl(string signedUrl, string filePath)
      {
          using (var client = new HttpClient())
          using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
          using (var content = new StreamContent(fileStream))
          {
              content.Headers.Add("Content-Type", "video/mp4");

              var response = await client.PutAsync(signedUrl, content);

              if (response.IsSuccessStatusCode)
              {
                  Console.WriteLine("File upload successful: " + response.StatusCode);
              }
              else
              {
                  Console.WriteLine("File upload failed: " + response.StatusCode);
              }
          }
      }
  }

  ```

  ```java Java theme={"system"}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.http.HttpRequest.BodyPublishers;
  import java.nio.file.Path;
  import java.io.IOException;
  import java.nio.file.Files;

  public class FileUploader {

      public static void main(String[] args) {
          String signedUrl = "SIGNED_URL"; // Replace with your signed URL
          String filePath = "LOCAL_FILE_PATH"; // Replace with your file path

          try {
              uploadFileToSignedUrl(signedUrl, filePath);
          } catch (IOException | InterruptedException e) {
              System.out.println("Error uploading file: " + e.getMessage());
          }
      }

      private static void uploadFileToSignedUrl(String signedUrl, String filePath) throws IOException, InterruptedException {
          HttpClient client = HttpClient.newHttpClient();
          HttpRequest request = HttpRequest.newBuilder()
                  .uri(URI.create(signedUrl))
                  .header("Content-Type", "image/jpg")
                  .PUT(BodyPublishers.ofFile(Path.of(filePath)))
                  .build();

          HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

          if (response.statusCode() == 200) {
              System.out.println("File upload successful: " + response.statusCode());
          } else {
              System.out.println("File upload failed: " + response.statusCode());
          }
      }
  }

  ```
</CodeGroup>

请务必确保创建 `uploadUrl` 时设置的 `contentType`,与 PUT 文件时使用的 Content-Type 及文件类型一致。
例如,如果创建 `uploadUrl` 时将 `contentType` 设为 "image/png",请务必设置 `Content-Type: image/png`,并且上传的文件以 `.png` 结尾。

上传成功时,将返回 `200` 响应。

### 在 Node.js 中上传二进制文件的示例

以下是使用 Node.js 上传二进制媒体文件的 JavaScript 示例:

```javascript theme={"system"}
const fs = require("fs");
const request = require("request");

const API_KEY = "Your API Key";
const fileName = "test.png";
const endpoint = `https://api.ayrshare.com/api/media/uploadUrl?fileName=${fileName}&contentType=png`;

const run = async () => {
  request.get(
    {
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${API_KEY}`
      },
      url: endpoint
    },
    (err, res, body) => {
      if (err) {
        return console.error(err);
      }

      const json = JSON.parse(body);
      console.log("Upload URL:", json);

      return fs.createReadStream(`./${fileName}`).pipe(
        request.put(
          json.uploadUrl,
          {
            headers: {
              "Content-Type": json.contentType
            }
          },
          (err, httpsResponse, body) => {
            if (err) {
              console.error("err", err);
            } else {
              console.log(body);
            }
          }
        )
      );
    }
  );
};

run();
```

### 在 Postman 中上传二进制文件的示例

你也可以使用 Postman 将二进制文件上传到 `uploadUrl`。

在 Postman 中:

1. 选择 HTTP 方法 `PUT`。
2. 将你的 `uploadUrl` 粘贴到 url 字段中。请注意,URL 会在一小时后过期,且只能使用一次。如果调用失败,你必须重新生成 `uploadUrl`。
3. 在 *Headers* 中,将 `Content-Type` 设置为 /uploadUrl 端点返回的 content type。例如:`Content-Type: image/png`。
4. 选择 *Body -> binary* 并选择要上传的文件。
5. 按下 **Send**。
6. **重要提示**:不会返回任何响应,因此你应通过在浏览器中打开 /uploadUrl 端点返回的 `accessUrl` 来检查上传是否成功。你也可以使用[验证 URL 端点](/apis/media/verify-media-url)。

<img class="center" src="https://mintcdn.com/ayrshare-docs/Nmrhj2Gh7WSf62Bh/images/apis/validate/postman%20binary.webp?fit=max&auto=format&n=Nmrhj2Gh7WSf62Bh&q=85&s=ca3def769242814afb17a58d9268667f" alt="Postman Binary Upload" width="1536" height="189" data-path="images/apis/validate/postman binary.webp" />

<Card title="Postman 示例 JSON 文件" icon="file" href="/files/Large Media File Upload.postman_collection.json" horizontal />

<ResponseExample>
  ```javascript 200: An upload URL and access URL theme={"system"}
  {
      "accessUrl": "https://media.ayrshare.com/Aswmfs3dIEbwLSdhTlV2/test.mp4",
      "contentType": "video/mp4",
      "uploadUrl": "https://storage.googleapis.com/..."
  }
  ```

  ```json 400: Bad Request Error getting signed URL theme={"system"}
  {
    "action": "upload",
    "status": "error",
    "code": 301,
    "message": "The provided content-type 'movd' is not recognized."
  }
  ```
</ResponseExample>
