tencentyun / image-java-sdk-v2.0

84 stars 73 forks source link

人脸检索时候使用FaceIdentifyRequest采用byte[]作为参数时报错 #14

Closed 510mt closed 5 years ago

510mt commented 5 years ago

封装的腾讯sdk接口

调用FaceIdentifyRequest并传入的是byte的图片文件时

 /**
     * 人脸检索 byte模式
     * @param image
     * @param groupIds
     * @return
     * @throws AbstractImageException
     * @throws IOException
     */
private QcloudFaceResult<IdentifyResult> faceIdentifyByte( byte[] image, String[] groupIds) throws AbstractImageException, IOException {

        FaceIdentifyRequest request = new FaceIdentifyRequest(CosBucketNameConst.bucketName, groupIds, image);

        String ret = imageClient.faceIdentify(request);

        return JsonUtil.json2pojo(ret, QcloudFaceResult.class, IdentifyResult.class);
}

定位到com.qcloud.image.op.DetectionOp这个类下,发现了未对byte[]类型的文件进行判断(url以及file形式的参数进行了判断)

public String faceIdentify(FaceIdentifyRequest request) throws AbstractImageException {
        request.check_param();
        String sign = Sign.appSign(this.cred, request.getBucketName(), (long)this.config.getSignExpired());
        String url = "https://" + this.config.getQCloudImageDomain() + this.config.getFaceIdentify();
        HttpRequest httpRequest = new HttpRequest();
        httpRequest.setUrl(url);
        httpRequest.addHeader("Authorization", sign);
        httpRequest.addHeader("User-Agent", this.config.getUserAgent());
        httpRequest.addParam("appid", String.valueOf(this.cred.getAppId()));
        httpRequest.addParam("bucket", request.getBucketName());
        httpRequest.setMethod(HttpMethod.POST);
        String groupId = request.getGroupId();
        String[] groupIds = request.getGroupIds();
        if (request.isUrl()) {  //对url进行
            httpRequest.addHeader("Content-Type", String.valueOf(HttpContentType.APPLICATION_JSON));
            httpRequest.addParam("url", request.getUrl());
            httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
            if (groupId != null && !groupId.isEmpty()) {
                httpRequest.addParam("group_id", groupId);
            } else {
                if (groupIds == null || groupIds.length <= 0) {
                    throw new ParamException("groupId and groupIds both null or empty!!");
                }

                httpRequest.addParam("group_ids", request.getGroupIds());
            }
        } else { 
            httpRequest.setContentType(HttpContentType.MULTIPART_FORM_DATA);
            httpRequest.addFile("image", request.getImage()); //这个位置不管传入的是byte还是file都addFile,若注入的是byte[]参数会引发后面一个错误
            BytesContent bytesContent = request.getBytesContent();
            if (bytesContent != null) {
                httpRequest.addBytes(bytesContent.getKey(), bytesContent.getContent());
            }

            if (groupId != null && !groupId.isEmpty()) {
                httpRequest.addParam("group_id", groupId);
            } else {
                if (groupIds == null || groupIds.length <= 0) {
                    throw new ParamException("groupId and groupIds both null or empty!!");
                }

                for(int index = 0; index < groupIds.length; ++index) {
                    String key = String.format("group_ids[%d]", index);
                    String data = groupIds[index];
                    httpRequest.addParam(key, data);
                }
            }
        }

        return this.httpClient.sendHttpRequest(httpRequest);
    }

错误定位到com.qcloud.image.http.DefaultImageHttpClient 这个位置的sendPostRequest方法,这里把空的file传入到一个hashmap中,并作为参数设值到了httpRequest中,执行httpClient.sendHttpRequest(httpRequest)这个方法进入到com.qcloud.image.http.AbstractImageHttpClient这个类

执行

public String sendHttpRequest(HttpRequest httpRequest) throws AbstractImageException {

        HttpMethod method = httpRequest.getMethod();
        if (method == HttpMethod.POST) {
            return sendPostRequest(httpRequest);//进入这个方法
        } else {
            throw new ParamException("Unsupported Http Method");
        }
    }

执行sendPostRequest(httpRequest)定位到com.qcloud.image.http.DefaultImageHttpClient这个类

在这个类中,因为前面hashmap传入了一个空的file,导致size>0,并引发了

if (file == null) {
                    throw new FileNotFoundException("File is null: " + key);
                }

这个错误。

private void setMultiPartEntity(MultipartBuilder multipartBuilder, Map<String, Object> params, Map<String, File> files, Map<String, byte[]> fileContents)
            throws FileNotFoundException {

        multipartBuilder.type(MultipartBuilder.FORM);
        for (String paramKey : params.keySet()) {
            multipartBuilder.addFormDataPart(paramKey, String.valueOf(params.get(paramKey)));
        }

        if (files.size() > 0) {
            for (String key : files.keySet()) {
                File file = files.get(key);
                if (file == null) {
                    throw new FileNotFoundException("File is null: " + key);
                }
                if (!file.exists()) {
                    throw new FileNotFoundException("File Not Exists: " + file.getAbsolutePath());
                }
                multipartBuilder.addPart(
                        Headers.of("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"", key, file.getName())),
                        RequestBody.create(MediaType.parse("image/jpg"), file)
                );
            }
        }

        for (String key : fileContents.keySet()) {
            byte[] content = fileContents.get(key);
            if (content != null && content.length > 0) {
                multipartBuilder.addPart(
                        //TODO file name not resolved
                        Headers.of("Content-Disposition", String.format("form-data; name=\"%s\"; filename=\"%s\"", key, "bytes" + System.currentTimeMillis())),
                        RequestBody.create(MediaType.parse("image/jpg"), content)
                );
            }
        }

    }

@@以上就是遇到的问题,还希望能把后台界面完善下,我上传person的信息,还有我组的相关信息,但是后台都看不到,这个问题很蛋疼,麻烦能关注下这个点。

JadenZiv commented 5 years ago
else if (httpRequest.getContentType() == HttpContentType.MULTIPART_FORM_DATA) {
            HashMap<String, File> imageList = httpRequest.getImageList();
            Map<String, Object> params = httpRequest.getParams();
            MultipartBuilder multipartBuilder = new MultipartBuilder();

            //修复腾讯sdk byte[]报错的bug
            if (httpRequest.getBytesContentList() != null) {
                imageList = new HashMap<>();
            }

            try {
                setMultiPartEntity(multipartBuilder, params, imageList, httpRequest.getBytesContentList());
            } catch (FileNotFoundException e) {
                throw new ParamException(e.getMessage());
            }

加一个判断就可以了,这个bug有点蛋疼,这个本人自己将sdk封装spring-boot-starter