首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Fine Uploader - Java端点

Fine Uploader - Java端点
EN

Stack Overflow用户
提问于 2016-04-09 12:21:28
回答 1查看 1K关注 0票数 0

有没有人有一个使用Fine Uploader和S3和Java端点的完整示例项目?

我正在尝试使用Fine Uploader将文件直接发送到AWS我猜我的端点S3或在客户端设置servlet时出现了问题。

Fine Uploader 5.6.0收到来自服务器的空或无效响应!Fine Uploader 5.6.0策略签名失败。收到来自服务器的空响应或无效响应!

我的端点: Servlet上传文件- http://www.example.com/uploadfiles

代码语言:javascript
复制
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.util.BinaryUtils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.apache.commons.codec.binary.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SuppressWarnings("serial")
public class S3UploadsServlet extends HttpServlet
{

    final static String AWS_SECRET_KEY = "MY_SECRET_KEY";
    final static String AWS_PUBLIC_KEY = "MY_PUBLIC_KEY";

    // Main entry point for POST requests from Fine Uploader.  This currently assumes delete file requests use the
    // default method of DELETE, but that can be adjusted.
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        if (req.getServletPath().endsWith("s3/signature"))
        {
            handleSignatureRequest(req, resp);
        }
        else if (req.getServletPath().endsWith("s3/success"))
        {
            handleUploadSuccessRequest(req, resp);
        }
    }

    // Main entry point for DELETE requests sent by Fine Uploader.
    @Override
    public void doDelete(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        String key = req.getParameter("key");
        String bucket = req.getParameter("bucket");

        resp.setStatus(200);

        AWSCredentials myCredentials = new BasicAWSCredentials(AWS_PUBLIC_KEY, AWS_SECRET_KEY);
        AmazonS3 s3Client = new AmazonS3Client(myCredentials);
        s3Client.deleteObject(bucket, key);
    }

    // Called by the main POST request handler if Fine Uploader has asked for an item to be signed.  The item may be a
    // policy document or a string that represents multipart upload request headers.
    private void handleSignatureRequest(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        resp.setStatus(200);

        JsonParser jsonParser = new JsonParser();
        JsonElement contentJson = jsonParser.parse(req.getReader());
        JsonObject jsonObject = contentJson.getAsJsonObject();

        if (req.getQueryString() != null && req.getQueryString().contains("v4=true")) {
            handleV4SignatureRequest(jsonObject, contentJson, req, resp);
        }
        else {
            handleV2SignatureRequest(jsonObject, contentJson, req, resp);
        }

        resp.setStatus(200);
    }

    private void handleV2SignatureRequest(JsonObject payload, JsonElement contentJson, HttpServletRequest req, HttpServletResponse resp) throws IOException{
        String signature;
        JsonElement headers = payload.get("headers");
        JsonObject response = new JsonObject();

        try
        {
            // If this is not a multipart upload-related request, Fine Uploader will send a policy document
            // as the value of a "policy" property in the request.  In that case, we must base-64 encode
            // the policy document and then sign it. The will include the base-64 encoded policy and the signed policy document.
            if (headers == null)
            {
                String base64Policy = base64EncodePolicy(contentJson);
                signature = sign(base64Policy);

                // Validate the policy document to ensure the client hasn't tampered with it.
                // If it has been tampered with, set this property on the response and set the status to a non-200 value.
                //response.addProperty("invalid", true);

                response.addProperty("policy", base64Policy);
            }

            // If this is a request to sign a multipart upload-related request, we only need to sign the headers,
            // which are passed as the value of a "headers" property from Fine Uploader.  In this case,
            // we only need to return the signed value.
            else
            {
                signature = sign(headers.getAsString());
            }

            response.addProperty("signature", signature);
            resp.getWriter().write(response.toString());
        }
        catch (Exception e)
        {
            resp.setStatus(500);
        }
    }

    private void handleV4SignatureRequest(JsonObject payload, JsonElement contentJson, HttpServletRequest req, HttpServletResponse resp) throws IOException{
        String signature = null;
        JsonElement headers = payload.get("headers");
        JsonObject response = new JsonObject();

        try
        {
            // If this is not a multipart upload-related request, Fine Uploader will send a policy document
            // as the value of a "policy" property in the request.  In that case, we must base-64 encode
            // the policy document and then sign it. The will include the base-64 encoded policy and the signed policy document.
            if (headers == null)
            {
                String base64Policy = base64EncodePolicy(contentJson);
                JsonArray conditions = payload.getAsJsonArray("conditions");
                String credentialCondition = null;
                for (int i = 0; i < conditions.size(); i++) {
                    JsonObject condition = conditions.get(i).getAsJsonObject();
                    JsonElement value = condition.get("x-amz-credential");
                    if (value != null) {
                        credentialCondition = value.getAsString();
                        break;
                    }
                }

                // Validate the policy document to ensure the client hasn't tampered with it.
                // If it has been tampered with, set this property on the response and set the status to a non-200 value.
//                response.addProperty("invalid", true);


                Pattern pattern = Pattern.compile(".+\\/(.+)\\/(.+)\\/s3\\/aws4_request");
                Matcher matcher = pattern.matcher(credentialCondition);
                matcher.matches();
                signature = getV4Signature(matcher.group(1), matcher.group(2), base64Policy);

                response.addProperty("policy", base64Policy);
            }

            // If this is a request to sign a multipart upload-related request, we only need to sign the headers,
            // which are passed as the value of a "headers" property from Fine Uploader.  In this case,
            // we only need to return the signed value.
            else
            {
                Pattern pattern = Pattern.compile(".+\\n.+\\n(\\d+)\\/(.+)\\/s3\\/aws4_request\\n(.+)", Pattern.DOTALL);
                Matcher matcher = pattern.matcher(headers.getAsString());
                matcher.matches();
                String canonicalRequest = matcher.group(3);
                String hashedCanonicalRequest = hash256(canonicalRequest);
                String stringToSign = headers.getAsString().replaceAll("(?s)(.+s3\\/aws4_request\\n).+", "$1" + hashedCanonicalRequest);

                // Validate the policy document to ensure the client hasn't tampered with it.
                // If it has been tampered with, set this property on the response and set the status to a non-200 value.
                // response.addProperty("invalid", true);

                signature = getV4Signature(matcher.group(1), matcher.group(2), stringToSign);
            }

            response.addProperty("signature", signature);
            resp.getWriter().write(response.toString());
        }
        catch (Exception e)
        {
            resp.setStatus(500);
        }
    }

    // Called by the main POST request handler if Fine Uploader has indicated that the file has been
    // successfully sent to S3.  You have the opportunity here to examine the file in S3 and "fail" the upload
    // if something in not correct.
    private void handleUploadSuccessRequest(HttpServletRequest req, HttpServletResponse resp) {
        String key = req.getParameter("key");
        String uuid = req.getParameter("uuid");
        String bucket = req.getParameter("bucket");
        String name = req.getParameter("name");

        resp.setStatus(200);
        System.out.println(String.format("Upload successfully sent to S3!  Bucket: %s, Key: %s, UUID: %s, Filename: %s",
                bucket, key, uuid, name));
    }

    private String getV4Signature(String date, String region, String stringToSign) throws Exception {
        byte[] kSecret = ("AWS4" + AWS_SECRET_KEY).getBytes("UTF8");
        byte[] kDate    = sha256Encode(date, kSecret);
        byte[] kRegion  = sha256Encode(region, kDate);
        byte[] kService = sha256Encode("s3", kRegion);
        byte[] kSigning = sha256Encode("aws4_request", kService);
        byte[] kSignature = sha256Encode(stringToSign, kSigning);
        return Hex.encodeHexString(kSignature);
    }

    private byte[] sha256Encode(String data, byte[] key) throws Exception  {
        String algorithm="HmacSHA256";
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(key, algorithm));
        return mac.doFinal(data.getBytes("UTF8"));
    }

    private String hash256(String data) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(data.getBytes());
        return bytesToHex(md.digest());
    }

    private String bytesToHex(byte[] bytes) {
        StringBuffer result = new StringBuffer();
        for (byte byt : bytes) result.append(Integer.toString((byt & 0xff) + 0x100, 16).substring(1));
        return result.toString();
    }

    private String base64EncodePolicy(JsonElement jsonElement) throws UnsupportedEncodingException{
        String policyJsonStr = jsonElement.toString();
        String base64Encoded = BinaryUtils.toBase64 (policyJsonStr.getBytes("UTF-8"));
        return base64Encoded;
    }

    private String sign(String toSign) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException{
        Mac hmac = Mac.getInstance("HmacSHA1");
        hmac.init(new SecretKeySpec(AWS_SECRET_KEY.getBytes("UTF-8"), "HmacSHA1"));
        String signature = BinaryUtils.toBase64 (hmac.doFinal(toSign.getBytes("UTF-8")));
        return signature;
    }
}

我的JSP页面:

代码语言:javascript
复制
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <link href="/mysite/uploader/fine-uploader-gallery.css" rel="stylesheet">
    <script src="/mysite/uploader/s3.jquery.fine-uploader.js"></script>
    <script type="text/template" id="qq-template-s3">
        <div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
            <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
                <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
            </div>
            <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
                <span class="qq-upload-drop-area-text-selector"></span>
            </div>
            <div class="qq-upload-button-selector qq-upload-button">
                <div>Upload a file</div>
            </div>
            <span class="qq-drop-processing-selector qq-drop-processing">
                <span>Processing dropped files...</span>
                <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
            </span>
            <ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
                <li>
                    <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
                    <div class="qq-progress-bar-container-selector qq-progress-bar-container">
                        <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
                    </div>
                    <span class="qq-upload-spinner-selector qq-upload-spinner"></span>
                    <div class="qq-thumbnail-wrapper">
                        <a class="preview-link" target="_blank">
                            <img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
                        </a>
                    </div>
                    <button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X</button>
                    <button type="button" class="qq-upload-retry-selector qq-upload-retry">
                        <span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
                        Retry
                    </button>

                    <div class="qq-file-info">
                        <div class="qq-file-name">
                            <span class="qq-upload-file-selector qq-upload-file"></span>
                            <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span>
                        </div>
                        <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
                        <span class="qq-upload-size-selector qq-upload-size"></span>
                        <button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">
                            <span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
                        </button>
                        <button type="button" class="qq-btn qq-upload-pause-selector qq-upload-pause">
                            <span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
                        </button>
                        <button type="button" class="qq-btn qq-upload-continue-selector qq-upload-continue">
                            <span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
                        </button>
                    </div>
                </li>
            </ul>

            <dialog class="qq-alert-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">Close</button>
                </div>
            </dialog>

            <dialog class="qq-confirm-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">No</button>
                    <button type="button" class="qq-ok-button-selector">Yes</button>
                </div>
            </dialog>

            <dialog class="qq-prompt-dialog-selector">
                <div class="qq-dialog-message-selector"></div>
                <input type="text">
                <div class="qq-dialog-buttons">
                    <button type="button" class="qq-cancel-button-selector">Cancel</button>
                    <button type="button" class="qq-ok-button-selector">Ok</button>
                </div>
            </dialog>
        </div>
    </script>

    <style>
        #fine-uploader-s3 .preview-link {
            display: block;
            height: 100%;
            width: 100%;
        }
    </style>

    <title>Fine Uploader S3 Demo</title>
</head>
<body>

    <div id="fine-uploader-s3"></div>

    <script>
        $('#fine-uploader-s3').fineUploaderS3({
                debug: true,
            template: 'qq-template-s3',
            request: {
                endpoint: "my_bucket.s3.amazonaws.com", 
                accessKey: "my_access_key"
            },
            signature: {
                endpoint: "http://www.example.com/uploadfiles"
            },
            uploadSuccess: {
                endpoint: "http://www.example.com/uploadfiles?success",
                params: {
                    isBrowserPreviewCapable: qq.supportedFeatures.imagePreviews
                }
            },
            iframeSupport: {
                localBlankPagePath: "/server/success.html"
            },
            cors: {
                expected: false
            },
            chunking: {
                enabled: true
            },
            resume: {
                enabled: true
            },
            deleteFile: {
                enabled: true,
                method: "POST",
                endpoint: "http://www.example.com/uploadfiles"
            },
            validation: {
                itemLimit: 5,
                sizeLimit: 15000000
            },
            thumbnails: {
                placeholders: {
                    notAvailablePath: "/uploader/placeholders/not_available-generic.png",
                    waitingPath: "/uploader/placeholders/waiting-generic.png"
                }
            },
            callbacks: {
                onComplete: function(id, name, response) {
                    var previewLink = qq(this.getItemByFileId(id)).getByClass('preview-link')[0];

                    if (response.success) {
                        previewLink.setAttribute("href", response.tempLink)
                    }
                }
            }
        });
    </script>
</body>
</html>
EN

回答 1

Stack Overflow用户

发布于 2016-04-14 04:14:04

答案是:

我刚刚在JSP中更改了端点URL:

代码语言:javascript
复制
signature: {
             endpoint: "http://www.mysite/uploadfiles?status=signature"
            },
            uploadSuccess: {
                endpoint: "http://www.mysite/uploadfiles?status=success",
                params: {
                    isBrowserPreviewCapable: qq.supportedFeatures.imagePreviews
                }
            }

Servlet - doPost方法中的条件结构:

代码语言:javascript
复制
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        if (req.getParameter("status").equals("signature"))
            handleSignatureRequest(req, resp);
        else if (req.getParameter("status").equals("success"))
            handleUploadSuccessRequest(req, resp);
    }

现在可以正常工作了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36512726

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档