作者:张医博
什么是 “跨域”
一句话简单说明
一个资源请求一个其它域名的资源时会发起一个跨域 HTTP 请求 (cross-origin HTTP request)。比如说,域名 A http://domaina.example
的某 Web 应用通过 <img>
标签引入了域名 B:http://domainb.foo
的某图片资源 http://domainb.foo/image.jpg
,域名 A 的 Web 应用会触发浏览器发起一个跨域 HTTP 请求。
demo
http://www. class="hljs-number">123.com/index.html 调用 http://www. class="hljs-number">123.com/server.php (非跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
跨域请求标识
origin ,当浏览器识别出 client 发起的请求需要转到另外一个域名上处理是,会在请求的 request header 中增加一个 origin 标识,如下我用 curl 测试了一个域名。
curl -voa http: class="hljs-comment">//mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/010/personal.jpg -H "Origin:www.mobby.cn"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 59.110.190.173...
TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com (59.110.190.173) port 80 (#0)
> GET /stu_avatar/010/personal.jpg HTTP/1.1
可以看到挡我发起 Origin 的请求头后,如果目标的网页服务允许来源的域名访问,就会在响应的 Response header 中带上跨域的响应头。(以下 header 目标域名如果设置了才会有响应)
< Access-Control-Allow-Origin: www.mobby.cn (允许的跨域来源,可以写 *,或者绝对域名)
< Access-Control-Allow-Headers: *(允许跨域时携带哪些 header )
< Access-Control-Allow-Methods: GET, POST, HEAD (允许哪些跨域请求方法,origin 是默认支持的)
常见案例分析
场景 一:CDN 访问 CDN 跨域被拦截
通过报错可以看出来 发起跨区域请求的源头 是 bo3.ai.com 加载了 www.ai.com 网站的资源,这两个域名都在 阿里云 cdn 加速。既然找到了请求目的 www.ai.com,那么直接检查下目的域名上是否新增了跨域头。这种情况基本都是目的域名没有加上允许的跨域头导致。
场景二:直传 OSS 引用 CDN 资源被拦截
用户直接上传到 OSS ,但是应用了 CDN 的域名时出现的跨域的报错,出现这种情况因为引用的 CDN 上没有配置跨域的属性所以报错,在 CDN 上配置好跨域参数后问题解决。
找到阿里 CDN 控制台对应的 CDN 域名,配置 http header 头,增加三个属性,如下:
场景三:CDN 回源到 OSS
这个问题比较特殊,拆分两部分说明;
出现这种情况,通过截图我们发现用户有两种请求,分别是 GET
和 POST
两种,由于 GET
好测试,我们先说 GET
;
GET:
出现跨域错误,首先就要检查原是否添加了跨域头,于是我们使用 curl 测试一下,如果最简单的 get 测试成功返回跨域头,说明目的 域名设置了跨域响应,如果测试失败说明原没有添加跨域响应。通过如下图很显然看到了目的添加了跨域头。
curl -voa http://mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/ class="hljs-number">010/personal.jpg -H "Origin:www.mo.cn"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 59.110.190.173...
TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com () port 80 (#0)
> GET /stu_avatar/010/personal.jpg HTTP/1.1
POST
通过 GET
测试发现 oss 是加了跨域头的,但是为什么 POST
请求就返回 405 呢?没有任何跨域头呢?用户反馈为什么手动 curl 测试也是失败。
curl -v -X POST -d '{"user":"xxx"}' http: class="hljs-comment">//mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/010/personal.jpg -H "Origin:www.mo.cn"
Note: Unnecessary use of -X or --request, POST is already inferred.
Trying 59.110.190.173...TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com (59.110.190.173) port 80 (#0)
> POST /stu_avatar/010/personal.jpg HTTP/1.1
upload completely sent off: 14 out of 14 bytes
< HTTP/1.1 405 Method Not Allowed
- 首先我们看 oss 对于
POST
的要求,看完我们就找到原因了。
https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.6.1008.5bb84b4e1JEoA4
结论:
- 请求的格式不是 RFC 标准规定的 content-type:multipart/form-data;
- 请求头不是内容不是 RFC 规定的表单域提交;
- 既然不是表单域,那么 OSS API 要求的 filename 参数肯定也不是放在最后一个选项。
JAVA 跨域请求源码
package com.alibaba.edas.carshop.OSS;
import javax.activation.MimetypesFileTypeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class OSSPostFile {
<span class="hljs-comment">// The local file path to upload.</span>
<span class="hljs-keyword">private</span> String localFilePath = <span class="hljs-string">"C:\\T\\1.txt"</span>;
<span class="hljs-comment">// OSS domain, such as http://oss-cn-hangzhou.aliyuncs.com</span>
<span class="hljs-keyword">private</span> String endpoint = <span class="hljs-string">"http://oss-cn-beijing.aliyuncs.com"</span>;
<span class="hljs-comment">// Access key Id. Please get it from https://ak-console.aliyun.com</span>
<span class="hljs-keyword">private</span> String accessKeyId = <span class="hljs-string">""</span>;
<span class="hljs-keyword">private</span> String accessKeySecret = <span class="hljs-string">""</span>;
<span class="hljs-comment">// The existing bucket name</span>
<span class="hljs-keyword">private</span> String bucketName = <span class="hljs-string">"您自己的bucket名称"</span>;
<span class="hljs-comment">// The key name for the file to upload.</span>
<span class="hljs-keyword">private</span> String key = <span class="hljs-string">"1.txt"</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">PostObject</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-comment">// append the 'bucketname.' prior to the domain, such as</span>
<span class="hljs-comment">// http://bucket1.oss-cn-hangzhou.aliyuncs.com.</span>
String urlStr = endpoint.replace(<span class="hljs-string">"http://"</span>, <span class="hljs-string">"http://"</span> + bucketName + <span class="hljs-string">"."</span>);
<span class="hljs-comment">// form fields</span>
Map<String, String> formFields = <span class="hljs-keyword">new</span> LinkedHashMap<String, String>();
<span class="hljs-comment">// key</span>
formFields.put(<span class="hljs-string">"key"</span>, <span class="hljs-keyword">this</span>.key);
<span class="hljs-comment">// Content-Disposition</span>
formFields.put(<span class="hljs-string">"Content-Disposition"</span>, <span class="hljs-string">"attachment;filename="</span> + localFilePath);
<span class="hljs-comment">// OSSAccessKeyId</span>
formFields.put(<span class="hljs-string">"OSSAccessKeyId"</span>, accessKeyId);
<span class="hljs-comment">// policy</span>
String policy = <span class="hljs-string">"{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [[\"content-length-range\", 0, 104857600000]]}"</span>;
String encodePolicy = <span class="hljs-keyword">new</span> String(Base64.encodeBase64(policy.getBytes()));
formFields.put(<span class="hljs-string">"policy"</span>, encodePolicy);
<span class="hljs-comment">// Signature</span>
String signaturecom = computeSignature(accessKeySecret, encodePolicy);
formFields.put(<span class="hljs-string">"Signature"</span>, signaturecom);
String ret = formUpload(urlStr, formFields, localFilePath);
System.out.println(<span class="hljs-string">"Post Object ["</span> + <span class="hljs-keyword">this</span>.key + <span class="hljs-string">"] to bucket ["</span> + bucketName + <span class="hljs-string">"]"</span>);
System.out.println(<span class="hljs-string">"post reponse:"</span> + ret);
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">computeSignature</span><span class="hljs-params">(String accessKeySecret, String encodePolicy)</span>
<span class="hljs-keyword">throws</span> UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException </span>{
<span class="hljs-comment">// convert to UTF-8</span>
<span class="hljs-keyword">byte</span>[] key = accessKeySecret.getBytes(<span class="hljs-string">"UTF-8"</span>);
<span class="hljs-keyword">byte</span>[] data = encodePolicy.getBytes(<span class="hljs-string">"UTF-8"</span>);
<span class="hljs-comment">// hmac-sha1</span>
Mac mac = Mac.getInstance(<span class="hljs-string">"HmacSHA1"</span>);
mac.init(<span class="hljs-keyword">new</span> SecretKeySpec(key, <span class="hljs-string">"HmacSHA1"</span>));
<span class="hljs-keyword">byte</span>[] sha = mac.doFinal(data);
<span class="hljs-comment">// base64</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String(Base64.encodeBase64(sha));
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">formUpload</span><span class="hljs-params">(String urlStr, Map<String, String> formFields, String localFile)</span> <span class="hljs-keyword">throws</span> Exception </span>{
String res = <span class="hljs-string">""</span>;
HttpURLConnection conn = <span class="hljs-keyword">null</span>;
String boundary = <span class="hljs-string">"9431149156168"</span>;
<span class="hljs-keyword">try</span> {
URL url = <span class="hljs-keyword">new</span> URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(<span class="hljs-number">5000</span>);
conn.setReadTimeout(<span class="hljs-number">30000</span>);
conn.setDoOutput(<span class="hljs-keyword">true</span>);
conn.setDoInput(<span class="hljs-keyword">true</span>);
conn.setRequestMethod(<span class="hljs-string">"POST"</span>);
conn.setRequestProperty(<span class="hljs-string">"User-Agent"</span>, <span class="hljs-string">"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"</span>);
conn.setRequestProperty(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"multipart/form-data; boundary="</span> + boundary);
OutputStream out = <span class="hljs-keyword">new</span> DataOutputStream(conn.getOutputStream());
<span class="hljs-comment">// text</span>
<span class="hljs-keyword">if</span> (formFields != <span class="hljs-keyword">null</span>) {
StringBuffer strBuf = <span class="hljs-keyword">new</span> StringBuffer();
Iterator<Entry<String, String>> iter = formFields.entrySet().iterator();
<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;
<span class="hljs-keyword">while</span> (iter.hasNext()) {
Entry<String, String> entry = iter.next();
String inputName = entry.getKey();
String inputValue = entry.getValue();
<span class="hljs-keyword">if</span> (inputValue == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">continue</span>;
}
<span class="hljs-keyword">if</span> (i == <span class="hljs-number">0</span>) {
strBuf.append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\""</span> + inputName + <span class="hljs-string">"\"\r\n\r\n"</span>);
strBuf.append(inputValue);
} <span class="hljs-keyword">else</span> {
strBuf.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\""</span> + inputName + <span class="hljs-string">"\"\r\n\r\n"</span>);
strBuf.append(inputValue);
}
i++;
}
out.write(strBuf.toString().getBytes());
}
StringBuffer strBuf1 = <span class="hljs-keyword">new</span> StringBuffer();
String callback = <span class="hljs-string">"{\"callbackUrl\":\"http://47.93.116.168/Revice.ashx\",\"callbackBody\":\"{\\\"bucket\\\"=${bucket},\\\"size\\\"=${size}}\"}"</span>;
<span class="hljs-keyword">byte</span>[] textByte = callback.getBytes(<span class="hljs-string">"UTF-8"</span>);
strBuf1.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
String callbackstr = <span class="hljs-keyword">new</span> String(Base64.encodeBase64(textByte));
strBuf1.append(<span class="hljs-string">"Content-Disposition: form-data; name=\"callback\"\r\n\r\n"</span> + callbackstr + <span class="hljs-string">"\r\n\r\n"</span>);
out.write(strBuf1.toString().getBytes());
<span class="hljs-comment">// file</span>
File file = <span class="hljs-keyword">new</span> File(localFile);
String filename = file.getName();
String contentType = <span class="hljs-keyword">new</span> MimetypesFileTypeMap().getContentType(file);
<span class="hljs-keyword">if</span> (contentType == <span class="hljs-keyword">null</span> || contentType.equals(<span class="hljs-string">""</span>)) {
contentType = <span class="hljs-string">"application/octet-stream"</span>;
}
StringBuffer strBuf = <span class="hljs-keyword">new</span> StringBuffer();
strBuf.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\"file\"; "</span> + <span class="hljs-string">"filename=\""</span> + filename + <span class="hljs-string">"\"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Type: "</span> + contentType + <span class="hljs-string">"\r\n\r\n"</span>);
out.write(strBuf.toString().getBytes());
DataInputStream in = <span class="hljs-keyword">new</span> DataInputStream(<span class="hljs-keyword">new</span> FileInputStream(file));
<span class="hljs-keyword">int</span> bytes = <span class="hljs-number">0</span>;
<span class="hljs-keyword">byte</span>[] bufferOut = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];
<span class="hljs-keyword">while</span> ((bytes = in.read(bufferOut)) != -<span class="hljs-number">1</span>) {
out.write(bufferOut, <span class="hljs-number">0</span>, bytes);
}
in.close();
<span class="hljs-keyword">byte</span>[] endData = (<span class="hljs-string">"\r\n--"</span> + boundary + <span class="hljs-string">"--\r\n"</span>).getBytes();
out.write(endData);
out.flush();
out.close();
<span class="hljs-comment">// Gets the file data</span>
strBuf = <span class="hljs-keyword">new</span> StringBuffer();
BufferedReader reader = <span class="hljs-keyword">new</span> BufferedReader(<span class="hljs-keyword">new</span> InputStreamReader(conn.getInputStream()));
String line = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">while</span> ((line = reader.readLine()) != <span class="hljs-keyword">null</span>) {
strBuf.append(line).append(<span class="hljs-string">"\n"</span>);
}
res = strBuf.toString();
reader.close();
reader = <span class="hljs-keyword">null</span>;
} <span class="hljs-keyword">catch</span> (Exception e) {
System.err.println(<span class="hljs-string">"Send post request exception: "</span> + e.getLocalizedMessage());
<span class="hljs-keyword">throw</span> e;
} <span class="hljs-keyword">finally</span> {
<span class="hljs-keyword">if</span> (conn != <span class="hljs-keyword">null</span>) {
conn.disconnect();
conn = <span class="hljs-keyword">null</span>;
}
}
<span class="hljs-keyword">return</span> res;
}
}
测试结果
场景四:
OSS 控制台配置跨域规则失败
初步分析:出现的原因是因为用户之前历史配置过的规则中含有特殊字符导致控制台拉取是否有历史配置时失败,响应了 invalidresponse。
解决方法:用户通过 SDK 修改跨域规则,通过 SDK 配置的规则将历史规则覆盖掉。
场景五:客户端使用 cavens 测试图片的跨域访问被 403
1、先确认 OSS 是否非配置了跨域头,配置的是否正确;
2、出现类似问题可以使用 postman 或者 curl 工具测试,看下是否同样出现问题。
3、如果发现本地测试跨域头都是正常的,只有客户端的浏览器测试异常,请用户清除浏览器缓存,开启隐私模式进行测试。
什么是 “跨域”
一句话简单说明
一个资源请求一个其它域名的资源时会发起一个跨域 HTTP 请求 (cross-origin HTTP request)。比如说,域名 A http://domaina.example
的某 Web 应用通过 <img>
标签引入了域名 B:http://domainb.foo
的某图片资源 http://domainb.foo/image.jpg
,域名 A 的 Web 应用会触发浏览器发起一个跨域 HTTP 请求。
demo
http://www. class="hljs-number">123.com/index.html 调用 http://www. class="hljs-number">123.com/server.php (非跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
跨域请求标识
origin ,当浏览器识别出 client 发起的请求需要转到另外一个域名上处理是,会在请求的 request header 中增加一个 origin 标识,如下我用 curl 测试了一个域名。
curl -voa http: class="hljs-comment">//mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/010/personal.jpg -H "Origin:www.mobby.cn"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 59.110.190.173...
TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com (59.110.190.173) port 80 (#0)
> GET /stu_avatar/010/personal.jpg HTTP/1.1
可以看到挡我发起 Origin 的请求头后,如果目标的网页服务允许来源的域名访问,就会在响应的 Response header 中带上跨域的响应头。(以下 header 目标域名如果设置了才会有响应)
< Access-Control-Allow-Origin: www.mobby.cn (允许的跨域来源,可以写 *,或者绝对域名)
< Access-Control-Allow-Headers: *(允许跨域时携带哪些 header )
< Access-Control-Allow-Methods: GET, POST, HEAD (允许哪些跨域请求方法,origin 是默认支持的)
常见案例分析
场景 一:CDN 访问 CDN 跨域被拦截
通过报错可以看出来 发起跨区域请求的源头 是 bo3.ai.com 加载了 www.ai.com 网站的资源,这两个域名都在 阿里云 cdn 加速。既然找到了请求目的 www.ai.com,那么直接检查下目的域名上是否新增了跨域头。这种情况基本都是目的域名没有加上允许的跨域头导致。
场景二:直传 OSS 引用 CDN 资源被拦截
用户直接上传到 OSS ,但是应用了 CDN 的域名时出现的跨域的报错,出现这种情况因为引用的 CDN 上没有配置跨域的属性所以报错,在 CDN 上配置好跨域参数后问题解决。
找到阿里 CDN 控制台对应的 CDN 域名,配置 http header 头,增加三个属性,如下:
场景三:CDN 回源到 OSS
这个问题比较特殊,拆分两部分说明;
出现这种情况,通过截图我们发现用户有两种请求,分别是 GET
和 POST
两种,由于 GET
好测试,我们先说 GET
;
GET:
出现跨域错误,首先就要检查原是否添加了跨域头,于是我们使用 curl 测试一下,如果最简单的 get 测试成功返回跨域头,说明目的 域名设置了跨域响应,如果测试失败说明原没有添加跨域响应。通过如下图很显然看到了目的添加了跨域头。
curl -voa http://mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/ class="hljs-number">010/personal.jpg -H "Origin:www.mo.cn"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 59.110.190.173...
TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com () port 80 (#0)
> GET /stu_avatar/010/personal.jpg HTTP/1.1
POST
通过 GET
测试发现 oss 是加了跨域头的,但是为什么 POST
请求就返回 405 呢?没有任何跨域头呢?用户反馈为什么手动 curl 测试也是失败。
curl -v -X POST -d '{"user":"xxx"}' http: class="hljs-comment">//mo-im.oss-cn-beijing.aliyuncs.com/stu_avatar/010/personal.jpg -H "Origin:www.mo.cn"
Note: Unnecessary use of -X or --request, POST is already inferred.
Trying 59.110.190.173...TCP_NODELAY setConnected to mo-im.oss-cn-beijing.aliyuncs.com (59.110.190.173) port 80 (#0)
> POST /stu_avatar/010/personal.jpg HTTP/1.1
upload completely sent off: 14 out of 14 bytes
< HTTP/1.1 405 Method Not Allowed
- 首先我们看 oss 对于
POST
的要求,看完我们就找到原因了。
https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.6.1008.5bb84b4e1JEoA4
结论:
- 请求的格式不是 RFC 标准规定的 content-type:multipart/form-data;
- 请求头不是内容不是 RFC 规定的表单域提交;
- 既然不是表单域,那么 OSS API 要求的 filename 参数肯定也不是放在最后一个选项。
JAVA 跨域请求源码
package com.alibaba.edas.carshop.OSS;
import javax.activation.MimetypesFileTypeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class OSSPostFile {
<span class="hljs-comment">// The local file path to upload.</span>
<span class="hljs-keyword">private</span> String localFilePath = <span class="hljs-string">"C:\\T\\1.txt"</span>;
<span class="hljs-comment">// OSS domain, such as http://oss-cn-hangzhou.aliyuncs.com</span>
<span class="hljs-keyword">private</span> String endpoint = <span class="hljs-string">"http://oss-cn-beijing.aliyuncs.com"</span>;
<span class="hljs-comment">// Access key Id. Please get it from https://ak-console.aliyun.com</span>
<span class="hljs-keyword">private</span> String accessKeyId = <span class="hljs-string">""</span>;
<span class="hljs-keyword">private</span> String accessKeySecret = <span class="hljs-string">""</span>;
<span class="hljs-comment">// The existing bucket name</span>
<span class="hljs-keyword">private</span> String bucketName = <span class="hljs-string">"您自己的bucket名称"</span>;
<span class="hljs-comment">// The key name for the file to upload.</span>
<span class="hljs-keyword">private</span> String key = <span class="hljs-string">"1.txt"</span>;
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">PostObject</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-comment">// append the 'bucketname.' prior to the domain, such as</span>
<span class="hljs-comment">// http://bucket1.oss-cn-hangzhou.aliyuncs.com.</span>
String urlStr = endpoint.replace(<span class="hljs-string">"http://"</span>, <span class="hljs-string">"http://"</span> + bucketName + <span class="hljs-string">"."</span>);
<span class="hljs-comment">// form fields</span>
Map<String, String> formFields = <span class="hljs-keyword">new</span> LinkedHashMap<String, String>();
<span class="hljs-comment">// key</span>
formFields.put(<span class="hljs-string">"key"</span>, <span class="hljs-keyword">this</span>.key);
<span class="hljs-comment">// Content-Disposition</span>
formFields.put(<span class="hljs-string">"Content-Disposition"</span>, <span class="hljs-string">"attachment;filename="</span> + localFilePath);
<span class="hljs-comment">// OSSAccessKeyId</span>
formFields.put(<span class="hljs-string">"OSSAccessKeyId"</span>, accessKeyId);
<span class="hljs-comment">// policy</span>
String policy = <span class="hljs-string">"{\"expiration\": \"2120-01-01T12:00:00.000Z\",\"conditions\": [[\"content-length-range\", 0, 104857600000]]}"</span>;
String encodePolicy = <span class="hljs-keyword">new</span> String(Base64.encodeBase64(policy.getBytes()));
formFields.put(<span class="hljs-string">"policy"</span>, encodePolicy);
<span class="hljs-comment">// Signature</span>
String signaturecom = computeSignature(accessKeySecret, encodePolicy);
formFields.put(<span class="hljs-string">"Signature"</span>, signaturecom);
String ret = formUpload(urlStr, formFields, localFilePath);
System.out.println(<span class="hljs-string">"Post Object ["</span> + <span class="hljs-keyword">this</span>.key + <span class="hljs-string">"] to bucket ["</span> + bucketName + <span class="hljs-string">"]"</span>);
System.out.println(<span class="hljs-string">"post reponse:"</span> + ret);
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">computeSignature</span><span class="hljs-params">(String accessKeySecret, String encodePolicy)</span>
<span class="hljs-keyword">throws</span> UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException </span>{
<span class="hljs-comment">// convert to UTF-8</span>
<span class="hljs-keyword">byte</span>[] key = accessKeySecret.getBytes(<span class="hljs-string">"UTF-8"</span>);
<span class="hljs-keyword">byte</span>[] data = encodePolicy.getBytes(<span class="hljs-string">"UTF-8"</span>);
<span class="hljs-comment">// hmac-sha1</span>
Mac mac = Mac.getInstance(<span class="hljs-string">"HmacSHA1"</span>);
mac.init(<span class="hljs-keyword">new</span> SecretKeySpec(key, <span class="hljs-string">"HmacSHA1"</span>));
<span class="hljs-keyword">byte</span>[] sha = mac.doFinal(data);
<span class="hljs-comment">// base64</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> String(Base64.encodeBase64(sha));
}
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">formUpload</span><span class="hljs-params">(String urlStr, Map<String, String> formFields, String localFile)</span> <span class="hljs-keyword">throws</span> Exception </span>{
String res = <span class="hljs-string">""</span>;
HttpURLConnection conn = <span class="hljs-keyword">null</span>;
String boundary = <span class="hljs-string">"9431149156168"</span>;
<span class="hljs-keyword">try</span> {
URL url = <span class="hljs-keyword">new</span> URL(urlStr);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(<span class="hljs-number">5000</span>);
conn.setReadTimeout(<span class="hljs-number">30000</span>);
conn.setDoOutput(<span class="hljs-keyword">true</span>);
conn.setDoInput(<span class="hljs-keyword">true</span>);
conn.setRequestMethod(<span class="hljs-string">"POST"</span>);
conn.setRequestProperty(<span class="hljs-string">"User-Agent"</span>, <span class="hljs-string">"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)"</span>);
conn.setRequestProperty(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"multipart/form-data; boundary="</span> + boundary);
OutputStream out = <span class="hljs-keyword">new</span> DataOutputStream(conn.getOutputStream());
<span class="hljs-comment">// text</span>
<span class="hljs-keyword">if</span> (formFields != <span class="hljs-keyword">null</span>) {
StringBuffer strBuf = <span class="hljs-keyword">new</span> StringBuffer();
Iterator<Entry<String, String>> iter = formFields.entrySet().iterator();
<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;
<span class="hljs-keyword">while</span> (iter.hasNext()) {
Entry<String, String> entry = iter.next();
String inputName = entry.getKey();
String inputValue = entry.getValue();
<span class="hljs-keyword">if</span> (inputValue == <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">continue</span>;
}
<span class="hljs-keyword">if</span> (i == <span class="hljs-number">0</span>) {
strBuf.append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\""</span> + inputName + <span class="hljs-string">"\"\r\n\r\n"</span>);
strBuf.append(inputValue);
} <span class="hljs-keyword">else</span> {
strBuf.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\""</span> + inputName + <span class="hljs-string">"\"\r\n\r\n"</span>);
strBuf.append(inputValue);
}
i++;
}
out.write(strBuf.toString().getBytes());
}
StringBuffer strBuf1 = <span class="hljs-keyword">new</span> StringBuffer();
String callback = <span class="hljs-string">"{\"callbackUrl\":\"http://47.93.116.168/Revice.ashx\",\"callbackBody\":\"{\\\"bucket\\\"=${bucket},\\\"size\\\"=${size}}\"}"</span>;
<span class="hljs-keyword">byte</span>[] textByte = callback.getBytes(<span class="hljs-string">"UTF-8"</span>);
strBuf1.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
String callbackstr = <span class="hljs-keyword">new</span> String(Base64.encodeBase64(textByte));
strBuf1.append(<span class="hljs-string">"Content-Disposition: form-data; name=\"callback\"\r\n\r\n"</span> + callbackstr + <span class="hljs-string">"\r\n\r\n"</span>);
out.write(strBuf1.toString().getBytes());
<span class="hljs-comment">// file</span>
File file = <span class="hljs-keyword">new</span> File(localFile);
String filename = file.getName();
String contentType = <span class="hljs-keyword">new</span> MimetypesFileTypeMap().getContentType(file);
<span class="hljs-keyword">if</span> (contentType == <span class="hljs-keyword">null</span> || contentType.equals(<span class="hljs-string">""</span>)) {
contentType = <span class="hljs-string">"application/octet-stream"</span>;
}
StringBuffer strBuf = <span class="hljs-keyword">new</span> StringBuffer();
strBuf.append(<span class="hljs-string">"\r\n"</span>).append(<span class="hljs-string">"--"</span>).append(boundary).append(<span class="hljs-string">"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Disposition: form-data; name=\"file\"; "</span> + <span class="hljs-string">"filename=\""</span> + filename + <span class="hljs-string">"\"\r\n"</span>);
strBuf.append(<span class="hljs-string">"Content-Type: "</span> + contentType + <span class="hljs-string">"\r\n\r\n"</span>);
out.write(strBuf.toString().getBytes());
DataInputStream in = <span class="hljs-keyword">new</span> DataInputStream(<span class="hljs-keyword">new</span> FileInputStream(file));
<span class="hljs-keyword">int</span> bytes = <span class="hljs-number">0</span>;
<span class="hljs-keyword">byte</span>[] bufferOut = <span class="hljs-keyword">new</span> <span class="hljs-keyword">byte</span>[<span class="hljs-number">1024</span>];
<span class="hljs-keyword">while</span> ((bytes = in.read(bufferOut)) != -<span class="hljs-number">1</span>) {
out.write(bufferOut, <span class="hljs-number">0</span>, bytes);
}
in.close();
<span class="hljs-keyword">byte</span>[] endData = (<span class="hljs-string">"\r\n--"</span> + boundary + <span class="hljs-string">"--\r\n"</span>).getBytes();
out.write(endData);
out.flush();
out.close();
<span class="hljs-comment">// Gets the file data</span>
strBuf = <span class="hljs-keyword">new</span> StringBuffer();
BufferedReader reader = <span class="hljs-keyword">new</span> BufferedReader(<span class="hljs-keyword">new</span> InputStreamReader(conn.getInputStream()));
String line = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">while</span> ((line = reader.readLine()) != <span class="hljs-keyword">null</span>) {
strBuf.append(line).append(<span class="hljs-string">"\n"</span>);
}
res = strBuf.toString();
reader.close();
reader = <span class="hljs-keyword">null</span>;
} <span class="hljs-keyword">catch</span> (Exception e) {
System.err.println(<span class="hljs-string">"Send post request exception: "</span> + e.getLocalizedMessage());
<span class="hljs-keyword">throw</span> e;
} <span class="hljs-keyword">finally</span> {
<span class="hljs-keyword">if</span> (conn != <span class="hljs-keyword">null</span>) {
conn.disconnect();
conn = <span class="hljs-keyword">null</span>;
}
}
<span class="hljs-keyword">return</span> res;
}
}
测试结果
场景四:
OSS 控制台配置跨域规则失败
初步分析:出现的原因是因为用户之前历史配置过的规则中含有特殊字符导致控制台拉取是否有历史配置时失败,响应了 invalidresponse。
解决方法:用户通过 SDK 修改跨域规则,通过 SDK 配置的规则将历史规则覆盖掉。
场景五:客户端使用 cavens 测试图片的跨域访问被 403
1、先确认 OSS 是否非配置了跨域头,配置的是否正确;
2、出现类似问题可以使用 postman 或者 curl 工具测试,看下是否同样出现问题。
3、如果发现本地测试跨域头都是正常的,只有客户端的浏览器测试异常,请用户清除浏览器缓存,开启隐私模式进行测试。