一.最近作阿里雲oss文件上傳開發,一點收穫分享給你們,幫助你們繞過一些坑。關於阿里雲oss服務的介紹,我這裏不作贅述了,能夠查看阿里雲OSS開發api文檔。php
在這裏我主要介紹下,文件上傳流程比較複雜的服務器設置回調功能。整個流程圖是這樣的:html
你們能夠參考阿里api文檔介紹的工做流程說明:https://help.aliyun.com/document_detail/31927.html?spm=5176.doc31988.6.633.OTY557java
二. 客戶端請求policy,簽名,key以及回調地址等web
1.首先定義咱們的業務類型biz_type,主要是將文件按業務類型目錄存儲。這裏我要着重強調一下,阿里oss回調請求的自定義參數:ajax
${x:biz_type},不要使用駝峯法命名,在開發的工程中,發現駝峯法命名bizType 取不到值。建議須要命名時 用"_"取代。
2.accessId ,accesskey 定義在properties文件中,這些定值從文件中讀取,這裏我要說明下:定義的end 和 endPoint
endpoint = http://oss-cn-shanghai.aliyuncs.com
end = oss-cn-shanghai.aliyuncs.comapache
bucket 是定義的桶名稱就相似於文件目錄名稱。json
2. callbackurl 定義本身的回調方法api
3.簽名,失效時間,policy,這些是根據阿里雲官網提供的案例代碼寫的。服務器
4.在定義callback字符串時,遇到一個大坑,這也是我寫整篇文章的緣由。app
定義callback 時,阿里支持兩種方式,一個是callbackBody字符串直接拼接 用&符鏈接。
這裏我使用的是第二種方式,callbackBody 採用json字符串。可是這跟以往的字符串不同,中間有阿里自帶的字符bucket,object,size等以及自定義的字符,ali oss 須要解析自定義字符,這裏能夠理解成
變量的一個佔位符,那麼json串是如何拼接一個佔位符變量呢???帶着這個問題,我就一遍一遍的拼串,嘗試了大概有兩小時,看了官網的一篇錯誤排查文章:https://yq.aliyun.com/articles/68863/
定義的回調字符串是這樣的:
{
"callbackUrl" : "http://abc.com/test.php", "callbackHost" : "oss-cn-hangzhou.aliyuncs.com", "callbackBody" : "{\"bucket\":${mimeType}, \"object\":${object},\"size\":${size},\"mimeType\":${mimeType},\"my_var\":${x:my_var}}", "callbackBodyType" : "application/json" }
頓時眼睛亮了,callbackBody 定義的原來是一個字符串的jsonobject,一直覺得須要定義一個佔位符類型的jsonobject對象。
"{\'bucket\':${bucket}, \'object\':${object},\'size\':${size},\'mimeType\':${mimeType},\'uid\':${x:uid},\'biz_type\':${x:biz_type}}"
最終將 resMap 轉成json 字符返回。 而後繼續拼串,定義的callbackBody就是這樣:
1 public String reqOssServer() throws ServletException, IOException { 2 3 String[] bizArray = new String[]{"","user-dir/","advise-dir/"}; 4 5 String biz_type = getRequest().getParameter("biz_type"); 6 7 String sysCurrtime = System.currentTimeMillis()+""; 8 9 //15位隨機碼 10 String randStr = sysCurrtime.substring(5,sysCurrtime.length())+CommonUtil.getRamdon(15); 11 //目錄 12 String dir = bizArray[Integer.valueOf(biz_type)]; 13 14 PropertiesUtil pro = new PropertiesUtil("oss.properties"); 15 String end = pro.readValue("end"); 16 String endpoint = pro.readValue("endpoint"); 17 String accessId = pro.readValue("accessKeyId"); 18 String accessKey = pro.readValue("accessKeySecret"); 19 String bucket = pro.readValue("bucketName"); 20 21 String host = "https://" + bucket + "." + end; 23 24 //oss 回調地址 25 String callbackurl = Cont.TEST_DOMAIN_NAME+"/osscallback"; 26 27 OSSClient client = new OSSClient(endpoint, accessId, accessKey); 28 try { 29 long expireTime = 3000; 30 long expireEndTime = System.currentTimeMillis() + expireTime * 100; 31 Date expiration = new Date(expireEndTime); 32 PolicyConditions policyConds = new PolicyConditions(); 33 policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); 34 policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); 35 36 String postPolicy = client.generatePostPolicy(expiration, policyConds); 37 byte[] binaryData = postPolicy.getBytes("utf-8"); 38 String encodedPolicy = BinaryUtil.toBase64String(binaryData); 39 String postSignature = client.calculatePostSignature(postPolicy); 40 41 42 Map<String, String> respMap = new LinkedHashMap<String, String>(); 43 URL url = client.generatePresignedUrl(bucket, accessKey, expiration); 44 respMap.put("accessid", accessId); 45 respMap.put("policy", encodedPolicy); 46 respMap.put("signature", postSignature); 47 //respMap.put("expire", formatISO8601Date(expiration)); 48 respMap.put("dir", dir); 49 respMap.put("host", host); 50 respMap.put("expire", String.valueOf(expireEndTime / 1000)); 51 respMap.put("url", url.toString()); 52 respMap.put("key", randStr); 53 //bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&my_var=${x:my_var} 54 /* String callback = "{\"callbackUrl\":\"" + callbackurl + "\",\"callbackBody\":\"filename=${object}&size=${size}&mimeType=${mimeType}&" 55 + "orderid=" + orderid + "&calbackright=" + calbackright + "\",\"callbackBodyType\":\"application/x-www-form-urlencoded\"}";*/ 56 //先傳入一個固定值測試 57 // String callback = "{\"callbackUrl\":\"" + callbackurl + "\",\"callbackBody\":\"filename=${object}&size=${size}&mimeType=${mimeType}&orderid=123\",\"callbackBodyType\":\"application/x-www-form-urlencoded\"}"; 58 59 //String callback = "{\"callbackUrl\":\""+callbackurl+"\",\"callbackBody\":\"{\'bucket\':${bucket}, \'object\':${object},\'size\':${size},\'mimeType\':${mimeType},\'uid\':${x:uid}}\",\"callbackBodyType\":\"application/json\"}"; 60 61 String callbackbody = "{\'bucket\':${bucket}, \'object\':${object},\'size\':${size},\'mimeType\':${mimeType},\'uid\':${x:uid},\'biz_type\':${x:biz_type}}"; 62 if("1".equals(biz_type)){//用戶頭像,banner修改 63 callbackbody = "{\'bucket\':${bucket}, \'object\':${object},\'size\':${size},\'mimeType\':${mimeType},\'uid\':${x:uid},\'biz_type\':${x:biz_type},\'portrait\':${x:portrait},\'banner\':${x:banner}}"; 64 }else if("2".equals(biz_type)){//投訴建議 65 callbackbody = "{\'bucket\':${bucket}, \'object\':${object},\'size\':${size},\'mimeType\':${mimeType},\'uid\':${x:uid},\'biz_type\':${x:biz_type},\'path\':${x:path},\'guideid\':${x:guideid}}"; 66 } 67 68 String callback = "{\"callbackUrl\":\""+callbackurl+"\",\"callbackBody\":\""+callbackbody+"\",\"callbackBodyType\":\"application/json\"}"; 69 70 byte[] bytes = Base64.encodeBase64(callback.getBytes("UTF-8")); 71 respMap.put("callback", new String(bytes)); 72 //respMap.put("callback_str", callback); 73 JSONObject ja1 = JSONObject.fromObject(respMap); 74 System.out.println("=====respMap:===== "+ja1.toString()); 75 getResponse().setHeader("Access-Control-Allow-Origin", "*"); 76 getResponse().setHeader("Access-Control-Allow-Methods", "GET, POST"); 77 78 setJsonString(AppJSON.succReq("請求成功", ja1.toString())); 79 } catch (Exception e) { 80 Assert.fail(e.getMessage()); 81 } 82 83 return "ajax"; 84 }
三. 回調方法處理業務邏輯
該回調方法是一個servlet,須要在web.xml中配置 訪問的路徑地址。在servlet中,主要進行業務處理,這裏就不在貼出個人業務處理了,你們根據本身的實際須要進行編碼。
1 package com.zd.servlet; 2 import java.io.BufferedReader; 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.net.URI; 7 import java.net.URL; 8 import java.security.KeyFactory; 9 import java.security.PublicKey; 10 import java.security.spec.X509EncodedKeySpec; 11 import java.text.ParseException; 12 import java.util.Date; 13 import javax.servlet.ServletException; 14 import javax.servlet.annotation.WebServlet; 15 import javax.servlet.http.HttpServlet; 16 import javax.servlet.http.HttpServletRequest; 17 import javax.servlet.http.HttpServletResponse; 18 import net.sf.json.JSONObject; 19 import org.apache.commons.lang.StringUtils; 20 import org.apache.http.HttpResponse; 21 import org.apache.http.client.methods.HttpGet; 22 import org.apache.http.impl.client.DefaultHttpClient; 23 import com.aliyun.oss.common.utils.BinaryUtil; 24 import com.zd.aliyun.oss.HttpMethod; 25 import com.zd.aliyun.oss.OSSClient; 26 import com.zd.aliyun.oss.common.utils.DateUtil; 27 import com.zd.aliyun.oss.model.GeneratePresignedUrlRequest; 28 import com.zd.util.Cont; 29 import com.zd.util.FileUtil; 30 import com.zd.util.StringUtil; 31 import com.zd.util.codeBuild.PropertiesUtil; 32 33 34 @SuppressWarnings("deprecation") 35 @WebServlet(asyncSupported = true) 36 public class OssCallBackService extends HttpServlet { 37 protected void doGet(HttpServletRequest req, HttpServletResponse resp) 38 throws ServletException, IOException { 39 this.doPost(req, resp); 40 response(req, resp, "input get ", 200); 41 } 44 45 @SuppressWarnings({ "finally" }) 46 public String executeGet(String url) { 47 BufferedReader in = null; 49 String content = null; 50 try { 51 // 定義HttpClient 52 @SuppressWarnings("resource") 53 DefaultHttpClient client = new DefaultHttpClient(); 54 // 實例化HTTP方法 55 HttpGet request = new HttpGet(); 56 request.setURI(new URI(url)); 57 HttpResponse response = client.execute(request); 58 59 in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); 60 StringBuffer sb = new StringBuffer(""); 61 String line = ""; 62 String NL = System.getProperty("line.separator"); 63 while ((line = in.readLine()) != null) { 64 sb.append(line + NL); 65 } 66 in.close(); 67 content = sb.toString(); 68 } catch (Exception e) { 69 } finally { 70 if (in != null) { 71 try { 72 in.close();// 最後要關閉BufferedReader 73 } catch (Exception e) { 74 e.printStackTrace(); 75 } 76 } 77 return content; 78 } 79 } 80 81 public String GetPostBody(InputStream is, int contentLen) { 82 if (contentLen > 0) { 83 int readLen = 0; 84 int readLengthThisTime = 0; 85 byte[] message = new byte[contentLen]; 86 try { 87 while (readLen != contentLen) { 88 readLengthThisTime = is.read(message, readLen, contentLen - readLen); 89 if (readLengthThisTime == -1) {// Should not happen. 90 break; 91 } 92 readLen += readLengthThisTime; 93 } 94 return new String(message); 95 } catch (IOException e) { 96 } 97 } 98 return ""; 99 } 100 101 //oss回調請求 102 protected boolean VerifyOSSCallbackRequest(HttpServletRequest request, String ossCallbackBody) throws NumberFormatException, IOException 103 { 104 boolean ret = false; 105 String autorizationInput = new String(request.getHeader("Authorization")); 106 String pubKeyInput = request.getHeader("x-oss-pub-key-url"); 107 byte[] authorization = BinaryUtil.fromBase64String(autorizationInput); 108 byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput); 109 String pubKeyAddr = new String(pubKey); 110 if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/") && !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")) 111 { 112 System.out.println("pub key addr must be oss addrss"); 113 return false; 114 } 115 String retString = executeGet(pubKeyAddr); 116 retString = retString.replace("-----BEGIN PUBLIC KEY-----", ""); 117 retString = retString.replace("-----END PUBLIC KEY-----", ""); 118 String queryString = request.getQueryString(); 119 String uri = request.getRequestURI(); 120 String decodeUri = java.net.URLDecoder.decode(uri, "UTF-8"); 121 String authStr = decodeUri; 122 if (queryString != null && !queryString.equals("")) { 123 authStr += "?" + queryString; 124 } 125 authStr += "\n" + ossCallbackBody; 126 ret = doCheck(authStr, authorization, retString); 127 return ret; 128 } 129 130 131 protected void doPost(HttpServletRequest request, HttpServletResponse response) 132 throws ServletException, IOException { 133 //HttpServletRequest 134 String ossCallbackBody = GetPostBody(request.getInputStream(), Integer.parseInt((request).getHeader("content-length"))); 135 System.out.println("ossCallbackBody == "+ossCallbackBody); 136 137 boolean ret = VerifyOSSCallbackRequest(request, ossCallbackBody); 138 System.out.println("verify result:" + ret); 139 140 // String aaa ="{\"bucket\":\"picture-zoomdu\",\"object\":\"2017072131713.jpg\",\"size\":\"12345\","gid":"86","uid":"121","type":"1"} 141 JSONObject obj = JSONObject.fromObject(ossCallbackBody); 142 PropertiesUtil pro = new PropertiesUtil("oss.properties"); 143 String endpoint = pro.readValue("endpoint"); 144 String accessKeyId = pro.readValue("accessKeyId"); 145 String accessKeySecret = pro.readValue("accessKeySecret"); 146 147 String bucketName = obj.get("bucket").toString(); 148 String bucketkey = obj.get("object").toString(); 149 150 OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret); 151 Date expirations = null; 152 try { 153 expirations = DateUtil.parseRfc822Date("Wed, 18 Mar 2019 14:20:00 GMT"); 154 } catch (ParseException e) { 155 e.printStackTrace(); 156 } 157 GeneratePresignedUrlRequest requestGenerate = new GeneratePresignedUrlRequest(bucketName, bucketkey, HttpMethod.GET); 158 requestGenerate.setExpiration(expirations); 159 160 URL signedUrl = ossClient.generatePresignedUrl(requestGenerate); 161 String path =signedUrl.toString(); 162 if(signedUrl.toString().indexOf("?")>-1){ 163 path = path.substring(0,signedUrl.toString().indexOf("?")); 164 } 165 // 圖片壓縮配置的字符串 166 path += "?x-oss-process=style/zd_list_image"; 167 String ossurl = "{\"ossurl\":\""+signedUrl.toString()+"\"}"; 168 if (ret){//簽名驗證經過,業務處理 169 //客戶端 在回調中須要 傳入的字段 171 172 response(request, response, "{\"Status\":\"OK\"}", HttpServletResponse.SC_OK); 173 //業務處理..... 此處省略 174 if(obj.containsKey("uid") && StringUtils.isNotEmpty(obj.get("uid")+"")){ 175 String uid = obj.get("uid").toString(); 176 //biz_type : 1:用戶頭像、banner ,2:投訴建議圖片上傳220 } 221 } 222 else{ 223 response(request, response, "{\"Status\":\"verdify not ok\"}", HttpServletResponse.SC_BAD_REQUEST); 224 } 226 } 227 229 public static boolean doCheck(String content, byte[] sign, String publicKey) { 230 try { 231 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 232 byte[] encodedKey = BinaryUtil.fromBase64String(publicKey); 233 PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); 234 java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA"); 235 signature.initVerify(pubKey); 236 signature.update(content.getBytes()); 237 boolean bverify = signature.verify(sign); 238 return bverify; 239 240 } catch (Exception e) { 241 e.printStackTrace(); 242 } 243 244 return false; 245 } 246 247 private void response(HttpServletRequest request, HttpServletResponse response, String results, int status) throws IOException { 248 String callbackFunName = request.getParameter("callback"); 249 System.out.println("callbackFunName:"+callbackFunName); 250 response.addHeader("Content-Length", String.valueOf(results.length())); 251 if (callbackFunName == null || callbackFunName.equalsIgnoreCase("")) 252 response.getWriter().println(results); 253 else 254 response.getWriter().println(callbackFunName + "( " + results + " )"); 255 response.setStatus(status); 256 response.flushBuffer(); 257 } 258 259 }
四.關於oss 上傳,並設置回調就介紹到這裏,本篇文章沒有介紹,oss服務配置,主要是講技術坑。若有什麼問題,請留言聯繫我,很樂意解決你們的問題。
另外鄭重說明,本篇文章是本人原創,如需轉載 請標註轉載原文地址。