使用Retrofit上传图片文件图片后台解析不出来 是哪里有问题吗

img

img

img

提交之后就是解析不出来 不知道是因为什么 有没有人做过这种的帮忙看一下

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 关于该问题,我找了一篇非常好的博客,你可以看看是否有帮助,链接:【Demo见真章】将安卓的Retrofit移植到鸿蒙系统上,在鸿蒙系统上实现一套网络请求框架
  • 除此之外, 这篇博客: Retrofit源码解析中的 方法注解的解析 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    RequestFactory.Builder::parseMethodAnnotation方法:

        private void parseMethodAnnotation(Annotation annotation) {
          if (annotation instanceof DELETE) {
            parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
          } else if (annotation instanceof GET) {
            parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
          } else if (annotation instanceof HEAD) {
            parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
          } else if (annotation instanceof PATCH) {
            parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
          } else if (annotation instanceof POST) {
            parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
          } else if (annotation instanceof PUT) {
            parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
          } else if (annotation instanceof OPTIONS) {
            parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
          } else if (annotation instanceof HTTP) {
            HTTP http = (HTTP) annotation;
            parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
          } else if (annotation instanceof retrofit2.http.Headers) {
            String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
            if (headersToParse.length == 0) {
              throw methodError(method, "@Headers annotation is empty.");
            }
            headers = parseHeaders(headersToParse);
          } else if (annotation instanceof Multipart) {
            if (isFormEncoded) {
              throw methodError(method, "Only one encoding annotation is allowed.");
            }
            isMultipart = true;
          } else if (annotation instanceof FormUrlEncoded) {
            if (isMultipart) {
              throw methodError(method, "Only one encoding annotation is allowed.");
            }
            isFormEncoded = true;
          }
        }
    

    这里对方法注解的处理方式主要可以分为三类:

    1. GETPOST等请求方法:调用RequestFactory.Builder::parseHttpMethodAndPath方法进行处理
    2. Headers的注解:调用RequestFactory.Builder::parseHeaders方法进行处理
    3. MultipartFormUrlEncoded注解:主要是在标记变量中进行记录

    我们看下第12步是如何处理的。

    GETPOST等请求方法的注解解析,使用RequestFactory.Builder::parseHttpMethodAndPath

    private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
        // 1.若已设置过httpMethod,则抛出异常
        if (this.httpMethod != null) {
            throw methodError(
                method,
                "Only one HTTP method is allowed. Found: %s and %s.",
                this.httpMethod,
                httpMethod);
        }
        // 记录 请求方法 及 是否有请求体
        this.httpMethod = httpMethod;
        this.hasBody = hasBody;
    
        // 若请求方法的注解(如GET)里面没有写值,则结束
        if (value.isEmpty()) {
            return;
        }
    
        // Get the relative URL path and existing query string, if present.
        // 2.判断请求方法的注解中的值是否合理,不合理则抛出异常
        int question = value.indexOf('?');
        if (question != -1 && question < value.length() - 1) {
            // Ensure the query string does not have any named parameters.
            String queryParams = value.substring(question + 1);
            // 使用正则表达式匹配
            Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
            if (queryParamMatcher.find()) {
                throw methodError(
                    method,
                    "URL query string \"%s\" must not have replace block. "
                    + "For dynamic query parameters use @Query.",
                    queryParams);
            }
        }
    
        // 3.记录相对Url;解析并记录注解中的占位符(parsePathParameters方法内部使用了正则表达式)
        this.relativeUrl = value;
        this.relativeUrlParamNames = parsePathParameters(value);
    }
    

    该方法主要做了下面的几件事情:

    1. 记录 请求方法 及 是否有请求体
    2. 判断请求方法的注解中的值是否合理,不合理则抛出异常
    3. 记录相对Url,解析并记录注解中的占位符

    我们以GET请求方法注解为例,第2步主要是防止GET的出现类似"users?sortby={sortby}"这种值,它希望我们动态设置的参数使用@Query注解来实现,举一个例子:

        @GET("/banner")
        fun getBanners(@Query("type") type: Int): Call<BannerJson>
    

    而不是

        @GET("/banner?type={type}")
        fun getBanners(@Path("type") type: Int): Call<BannerJson>
    

    3步,例如我们的请求方法为

    interface IUser {
        @GET("/users/{nickname}")
        fun getUser(@Path("nickname") nickname: String): Call<User>
    }
    

    那么计算后的值为

    // 相对url
    this.relativeUrl = "/users/{nickname}" 
    // 也就是{}包裹的值,如果有多个{},那么Set<String>会有多个值
    this.relativeUrlParamNames = 包含"nickname"的Set<String> 
    

    Headers注解的解析,使用RequestFactory.Builder::parseHeaders方法:

        private Headers parseHeaders(String[] headers) {
          // 这是okhttp3的Headers.Builder  
          Headers.Builder builder = new Headers.Builder();
          // 遍历传入的headers
          for (String header : headers) {
            int colon = header.indexOf(':');
            if (colon == -1 || colon == 0 || colon == header.length() - 1) {
              throw methodError(
                  method, "@Headers value must be in the form \"Name: Value\". Found: \"%s\"", header);
            }
            // 获取Header名和Header值  
            String headerName = header.substring(0, colon);
            String headerValue = header.substring(colon + 1).trim();
            // 如果Header是"Content-Type",则会进行一些特殊处理
            if ("Content-Type".equalsIgnoreCase(headerName)) {
              try {
                contentType = MediaType.get(headerValue);
              } catch (IllegalArgumentException e) {
                throw methodError(method, e, "Malformed content type: %s", headerValue);
              }
            } else {
              // 将Header添加到builder中  
              builder.add(headerName, headerValue);
            }
          }
          // 返回okhttp3.Headers  
          return builder.build();
        }
    

    该方法主要做的事情:将传入的字符串数组headers,构造为okhttp3.Headers并返回,对于Content-Type类型的Header,会进行一些特殊的处理。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^