阿里云内容设计中心

阿里云产品优质内容聚集地。各种最佳实践,问答,产品体验活动等你来发现~

base64先转码成指定格式图片,然后调用OSS上传接口进行上传。更多信息,请参见Github示例

/**
 * base64 to file
 * @param dataurl   base64 content
 * @param filename  set up a meaningful suffix, or you can set mime type in options
 * @returns {File|*}
 */
const dataURLtoFile = function dataURLtoFile(dataurl, filename) {
  const arr = dataurl.split(',');
  const mime = arr[0].match(/:(.*?);/)[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], { type: mime });// if env support File, also can use this: return new File([u8arr], filename, { type: mime });
};

// client表示OSS client实例
const uploadBase64Img = function uploadBase64Img(client) {
  // base64格式的内容
  const base64Content = 'data:image:xxxxxxxxxxxxx';
  const filename =  'img.png';
  const imgfile = dataURLtoFile(base64Content, filename);
  //key表示上传的object key ,imgFile表示dataURLtoFile处理后返回的图片
  client.multipartUpload(key, imgfile).then((res) => {
    console.log('upload success: %j', res);
  }).catch((err) => {
    console.error(err);
  });
};
            
cattt 评论 0

给要上传的Object名称前加指定目录前缀即可。更多信息,请参见OSS和文件系统对比

let OSS = require('ali-oss')
let client = new OSS({
  region: '<Your region>',
  accessKeyId: '<Your AccessKeyId>',
  accessKeySecret: '<Your AccessKeySecret>',
  bucket: 'Your bucket name'
});

client.multipartUpload('base-dir/' +'object-key', 'local-file', {
    progress: async function (p) {
      console.log('Progress: ' + p);
    }
  });
  console.log(result);
}).catch((err) => {
  console.log(err);
});

            
cattt 评论 0

初始化SDK时,可传入以下几个参数:


const client = new OSS({
region,
accessKeyId: creds.AccessKeyId,
accessKeySecret: creds.AccessKeySecret,
stsToken: creds.SecurityToken,
bucket,
secure:true
});
  • endpoint:例如http://oss-cn-hangzhou.aliyuncs.com,如果指定了endpoint,则region会被忽略,endpoint可以指定HTTPS,也可以是IP形式。
cattt 评论 0

1

回答

给要上传的 object 名称前加指定目录前缀即可,可参考OSS 和文件系统对比

let OSS = require('ali-oss')
let client = new OSS({
  region: '<Your region>',
  accessKeyId: '<Your AccessKeyId>',
  accessKeySecret: '<Your AccessKeySecret>',
  bucket: '<Your bucket name>',
});

client.multipartUpload('base-dir/' +'object-name', 'local-file', {
    progress: async function (p) {
      console.log('Progress: ' + p);
    }
  });
  console.log(result);
}).then((res) => {
  console.log(res)
}). catch((err) => {
  console.log(err);
});

			
cattt 评论 0

使用分片上传时,可通过progress参数获取上传进度。

cattt 评论 0

客户端部署tcpdump抓包,然后通过tcp报文排查是否由于Header信息不正确导致计算签名与服务端不匹配。

POST /ttsservice%2Fpasswd?uploadId=D468E486D1D94D90A1AB8885A4E32AE0 HTTP/1.1
Host: rokid.oss-cn-hangzhou.aliyuncs.com
Accept-Encoding: identity
Accept: text/html
Content-Length: 137
date: Sat, 29 Dec 2018 07:32:34 GMT
authorization: OSS LTAIknFr:r2KPR0y4E0G5tnU/MYdcvXHP****
Content-Type: application/x-www-form-urlencoded
User-Agent: aliyun-sdk-python/2.6.0(Linux/4.4.0-31-generic/x86_64;3.4.3)

<CompleteMultipartUpload><Part><PartNumber>1</PartNumber><ETag>"3195544E19D99658706D5****"</ETag></Part></CompleteMultipartUpload>HTTP/1.1 403 Forbidden

Server: AliyunOSS
Date: Sat, 29 Dec 2018 07:33:43 GMT
Content-Type: application/xml
Content-Length: 1122
Connection: keep-alive
x-oss-request-id: 5C2723573183****
x-oss-server-time: 0

<?xml version="1.0" encoding="UTF-8"?>
<Error>
 <Code>SignatureDoesNotMatch</Code>
 <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
 <RequestId> 5C2723573183A12D </RequestId>
 <HostId>rokid.oss-cn-hangzhou.aliyuncs.com</HostId>
 <OSSAccessKeyId> LTAXXX </OSSAccessKeyId>
 <SignatureProvided>r2KPR0y4E0G5tnU/MYdc****</SignatureProvided>
 <StringToSign>POST
application/x-www-form-urlencoded
Sat, 29 Dec 2018 07:32:34 GMT
/rokid/ttsservice/passwd?uploadId=D468E486D1D94D90A1AB8885A4E3****</StringToSign>
 <StringToSignBytes>50 4F 53 54 0A 0A 61 70 70 6C 69 63 61 74 69 6F 6E 2F 78 2D 77 77 77 2D 66 6F 72 6D 2D 75 72 6C 65 6E 63 6F 64 65 64 0A 53 61 74 2C 20 32 39 20 44 65 63 20 32 30 31 38 20 30 37 3A 33 32 3A 33 34 20 47 4D 54 0A 2F 72 6F 6B 69 64 2D 6F 70 73 2D 6D 6F 64 65 6C 2F 74 74 73 73 65 72 76 69 63 65 2F 70 61 73 73 77 64 3F 75 70 6C 6F 61 64 49 64 3D 44 34 36 38 45 34 38 36 44 31 44 39 34 44 39 30 41 31 41 42 38 38 38 35 41 34 45 33 32 41 45 30 </StringToSignBytes>
</Error>

如果服务端收到的签名(Signature)和客户端计算的签名信息不一致,说明请求的内容已被改动,建议使用HTTPS的方式上传。

以上是客户端抓取的报文信息。请将获取的请求头信息带入以下脚本,并将计算结果与SDK进行比较。

import base64
import hmac
import sha
mac = hmac.new("<Secretkey>","POST\n\napplication/x-www-form-urlencoded\nSat, 29 Dec 2018 07:32:34 GMT\n/rokid/ttsservice/passwd?uploadId=D468E486D1D94D90A1AB8885A4E3****", sha)
Signature = base64.b64encode(mac.digest())
print(Signature)

如果抓包数据和脚本计算的结果一致,则说明SDK计算正确。如果抓包数据和脚本计算的结果不一致,可能是因为SDK在Ubuntu平台编译的适配问题导致MD5值不一样。

cattt 评论 0
  • 错误原因

调用OSS Java SDK的程序,运行一段时间(根据业务量,几小时到几天不等)后内存泄露。 推荐使用Eclipse Memory Analyzer (MAT)分析内存使用情况。更多信息,请参见使用MAT进行堆转储文件分析

如果分析结果类似下图所示(PoolingHttpClientConnectionManager占96%的内存),原因是程序中可能多次执行new OSSClient,但是没有调用ossClient.shutdown,造成内存泄漏。

  • 解决方法

new OSSClient操作完成后,请通过shutdown进行关闭,保证new OSSClient和ossClient.shutdown成对使用。

cattt 评论 0
  • 错误原因

调用OSS Java SDK不响应。通过jstack -l pid命令查看堆栈,问题出现在如下的位置:

"main" prio=6 tid=0x000000000291e000 nid=0xc40 waiting on condition [0x0000000002dae000]
java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007d85697f8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
    at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:138)
    at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:306)
    at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64)
    at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:192)
    at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:185)
    at org.apache.http.pool.PoolEntryFuture.get(PoolEntryFuture.java:107)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.leaseConnection(PoolingHttpClientConnectionManager.java:276)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager$1.get(PoolingHttpClientConnectionManager.java:263)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:190)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at com.aliyun.oss.common.comm.DefaultServiceClient.sendRequestCore(DefaultServiceClient.java:113)
    at com.aliyun.oss.common.comm.ServiceClient.sendRequestImpl(ServiceClient.java:123)
    at com.aliyun.oss.common.comm.ServiceClient.sendRequest(ServiceClient.java:68)
    at com.aliyun.oss.internal.OSSOperation.send(OSSOperation.java:94)
    at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:146)
    at com.aliyun.oss.internal.OSSOperation.doOperation(OSSOperation.java:113)
    at com.aliyun.oss.internal.OSSObjectOperation.getObject(OSSObjectOperation.java:229)
    at com.aliyun.oss.OSSClient.getObject(OSSClient.java:629)
    at com.aliyun.oss.OSSClient.getObject(OSSClient.java:617)
    at samples.HelloOSS.main(HelloOSS.java:49)
                    

原因是连接池中连接泄漏,可能是使用ossObject后没有关闭。

  • 解决方法

请检查您的程序,确保没有连接泄漏。关闭方法如下:

// 读取文件
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
// OSS操作
// 关闭ossObject
ossObject.close();
                    

问题排查的具体步骤,请参见OSS Java SDK不响应问题排查

cattt 评论 0
  • 错误原因1

1、AccessKey ID和AccssKey Secret不一致。

2、有关获取AccessKey ID和AccssKey Secret的操作步骤,请参见获取AccessKey。

  • 错误原因2

签名URL使用不正确。错误示例如下:

GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, object);
request.setExpiration( new Date(new Date().getTime() + 3600 * 1000));
request.addUserMetadata("author");
URL url = ossClient.generatePresignedUrl(request);

Map<String, String> header = new HashMap<String, String>();
header.put("author");
ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);

未指定Method参数时,默认使用GET方法。以上为PutObject请求,应指定Method参数并设置为PUT方法。

通过PutObject发送请求时,请求Header中自定义的元数据必须以x-oss-meta-为前缀。以上示例中自定义元数据应改为x-oss-meta-author。

解决方法:

指定Method,并修改Header:

request.addUserMetadata("author");
request.setMethod(HttpMethod.PUT);
URL url = ossClient.generatePresignedUrl(request);

Map<String, String> header = new HashMap<String, String>();
header.put("x-oss-meta-" + "author");
ossClient.putObject(url, new ByteArrayInputStream("Hello OSS".getBytes()), -1, header);
  • 错误原因3

1、使用了低于3.7.0版本的OSS SDK,项目中引入了4.5.9及以上版本的httpclient。

2、上传的文件名中包含+字符,而4.5.9版本的httpclient不会对+进行URLEncode编码,从而造成客户端与服务端计算的签名不一致而报错。

解决方法:

1、OSS SDK建议升级为3.11.1及以上版本, 以兼容4.5.9版本的httpclient。

2、移除多余的httpclient依赖。引入OSS SDK时会自动引入httpclient依赖,如果是第三方库另外引入了httpclient,请参见包冲突解决方案。

  • 错误原因4

HttpClient 4.5.10版本不支持Header中包含ISO/9959-1标准以外的字符,但在项目中引入了4.5.10以上的httpclient,并在请求Header中包含了ISO/9959-1标准以外的字符,例如x-oss-meta-开头的自定义元数据中传入了中文字符。

解决方法:

1、参见包冲突解决方案,移除冲突的httpclient版本。

2、在请求Header中传入符合ISO/9959-1标准的字符。

cattt 评论 0

您可以使用ossutil工具快速定位错误原因并解决问题。

cattt 评论 0

公告

阿里云内容设计团队出没于此,一大波优质阿里云相关内容随时袭来~

展开