1.26 问题调查

优质
小牛编辑
129浏览
2023-12-01

这里记录我们的用户在使用FDS过程中常出现的问题和调查手段

预签名链接使用相关

使用预签名链接发送请求的http方法头部信息 必须与生成预签名时传入的参数一致。如果不一致,服务端在校验发现错误时会返回403http返回码。
部分http库会根据上传的文件名后缀自动添加content-type头部。
建议初次调试的开发者使用SDK生成用于上传或下载的预签名链接,然后用命令行工具curl校验链接是否可用。
假设使用下面Java代码生成预签名URLYOUR_PRESIGNED_URL

package com.xiaomi.infra.galaxy.fds.example;

import java.io.IOException;
import java.net.URI;
import java.util.Date;

import com.xiaomi.infra.galaxy.fds.client.FDSClientConfiguration;
import com.xiaomi.infra.galaxy.fds.client.GalaxyFDS;
import com.xiaomi.infra.galaxy.fds.client.GalaxyFDSClient;
import com.xiaomi.infra.galaxy.fds.client.credential.BasicFDSCredential;
import com.xiaomi.infra.galaxy.fds.client.credential.GalaxyFDSCredential;
import com.xiaomi.infra.galaxy.fds.client.exception.GalaxyFDSClientException;
import com.xiaomi.infra.galaxy.fds.model.HttpMethod;

public class FDSClient {

  private static final String APP_ACCESS_KEY = ""; // AppKey
  private static final String APP_ACCESS_SECRET = ""; // AppSecret

  private static final String BUCKET_NAME = ""; // 创建的Bucket名字
  private static final String OBJECT_NAME = ""; // 上传的Object名字

  public static void main(String[] args)
      throws GalaxyFDSClientException, IOException {
    GalaxyFDSCredential credential = new BasicFDSCredential(
        APP_ACCESS_KEY, APP_ACCESS_SECRET);

    // Construct the GalaxyFDSClient object
    // set endpoint according to your needs.
    String endpoint = "awsbj0.fds.api.xiaomi.com"; // 确认与Bucket所在region一致
    FDSClientConfiguration fdsConfig = new FDSClientConfiguration(endpoint);
    fdsConfig.enableHttps(true);
    // do not upload object via cdn in this client
    fdsConfig.enableCdnForUpload(false);
    // download object via cdn in this client
    fdsConfig.enableCdnForDownload(true);
    GalaxyFDS fdsClient = new GalaxyFDSClient(credential, fdsConfig);

    // 生成预签名链接,用于上传文件到指定bucket下
    URI uri = fdsClient.generatePresignedUri(BUCKET_NAME, "OBJECT_NAME",
        new Date(System.currentTimeMillis() + 1000 * 20 * 60), HttpMethod.PUT);
    System.out.println(uri.toASCIIString());
  }
}

下面是用curl命令上传

curl -v -X PUT -H "Content-Type:" 'YOUR_PRESIGNED_URL' -d 'Testing presigned url'

样例输出:

curl -v -X PUT -H "Content-Type:" 'https://awsbj0.fds.api.xiaomi.com/fds-demo/test.txt?GalaxyAccessKeyId=5xxxxxxx45&Expires=1486192975555&Signature=H3xxxxxxxQ=' -d 'Testing presigned url'
...
> PUT /fds-demo/test.txt?GalaxyAccessKeyId=5411741548045&Expires=1486192975555&Signature=H3xxxxxxxQ= HTTP/1.1
> User-Agent: curl/7.35.0
> Host: awsbj0.fds.api.xiaomi.com
> Accept: */*
> Content-Length: 21
> 
...
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Content-MD5
< Access-Control-Allow-Methods: GET, POST, PUT, HEAD, DELETE, OPTIONS
< Access-Control-Expose-Headers: content-md5, upload-time, x-xiaomi-meta-content-length
< Access-Control-Max-Age: 1728000
< Content-Type: application/json
< Date: Sat, 04 Feb 2017 07:07:02 GMT
* Server Tengine is not blacklisted
< Server: Tengine
< Content-Length: 146
< Connection: keep-alive
< 
* Connection #0 to host awsbj0.fds.api.xiaomi.com left intact
{"accessKeyId":"54xxxxxx45","bucketName":"fds-demo","expires":1488784022611,"objectName":"test.txt","signature":"fA7rxxxxxxxxgI="}

如果用上面命令测试没有问题,但是使用自己的http库上传时出现403,请使用tcpdump等工具查看实际发出http请求是否与上面命令发出请求一致。
如果还是有问题,请将curl命令的输出以及抓取的http库上传数据给我们

分片上传

使用分片上传前,请仔细阅读相关限制

  • 如果上传的分片数过多(超过400个),服务端将会返回400
  • 如果上传的非最后一个分片过小(小于5MB),服务端将会返回400
  • 如果上传的分片过大,服务端将会返回400
  • 如果在complete阶段上传的分片列表中的分片号有缺失/重复,服务端将会返回400
  • 如果您使用的是老版本的android/iOS SDK,请确认FDSClientConfiguration::uploadPartSize被设置为大于5 * 1024 * 1024 可以参考获取网络请求内容方法查看是否出现以上问题。
    如果还是有问题,请将抓取的分片上传各个阶段收到/发送的数据给我们

资源授权/返回码403

正确把Bucket或者Object的权限给某个帐号后,用该帐号的Access Key,Secret Key发送请求时出现403。

  • 检查已经按照快速入门的介绍填写了正确的GranteeId
  • 确认密钥依然有效
  • 确认授权的Bucket与访问的是同一个Bucket
  • 确认授权的Bucket与访问的Bucket在同一个region
  • 确认访问的Object名称中不以\开头且不包含\\

获取网络请求内容方法

在调式过程中,可以通过抓取网络包,或者启用客户端日志查看从服务端接受的请求数据和发送给服务器的请求数据
下面是linux下抓取网络请求的方法(前提是使用http而不是https),假设访问的域名是cnbj0.fds.api.xiaomi.com。如果您不知道访问的域名,可以去掉host cnbj0.fds.api.xiaomi.com。在发送完请求后按下ctrl-c结束

sudo tcpdump -A host cnbj0.fds.api.xiaomi.com > tcpdump.log

如果使用的是FDS Java SDK,可以设置下面属性

System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
System.setProperty("org.apache.commons.logging.simplelog.log.httpclient.wire", "debug");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug");
System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.headers", "debug");
System.setProperty("log4j.rootLogger", "INFO, stdout");

其他方法