【问题标题】:Rest API can be called from Postman, shows 400 bad request from Java可以从 Postman 调用 Rest API,显示来自 Java 的 400 bad request
【发布时间】:2020-12-14 09:02:47
【问题描述】:

我正在尝试使用 POST 宁静服务。当我在 Postman 上尝试时,我得到了成功的响应。但是,当我使用以下代码在 java 上尝试时,我得到响应代码 400。在邮递员中,我通过替换转义字符粘贴相同的输入。

try {

    URL url = new URL("https://localhost/PasswordVault/api/Accounts");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoOutput(true);

    conn.setRequestProperty("Content-Type", "application/json");
    String input = "{\"qty\":100,\"name\":\"iPad 4\", \"detail\":{\"ver\":\"2020\",\"productionDate\":\"2020\"}}";

    OutputStream os = conn.getOutputStream();
    os.write(input.getBytes());
    os.flush();


    if (conn.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
        throw new RuntimeException("Failed : HTTP error code : "
                + conn.getResponseCode());
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

    String output;
    System.out.println("Output from Server .... \n");
    while ((output = br.readLine()) != null) {
        System.out.println(output);
    }

    conn.disconnect();
} catch (Exception e) {
        System.out.println("Exception:- " + e);
}

【问题讨论】:

    标签: java rest


    【解决方案1】:

    我强烈建议您为此使用库。 您可以使用 Jackson,这极大地简化和标准化了 java 与远程 HTTP 服务的交互。

    这些方面的东西会让你开始:

    import javax.ws.rs.client.Client;
    import javax.ws.rs.client.ClientBuilder;
    import javax.ws.rs.client.Entity;
    import javax.ws.rs.client.WebTarget;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Response;
    
    public class ApiClient
    {
    
        private transient Client client;
        protected transient WebTarget apiRoot;
    
        public ApiClient(String rootUrl) 
        {
            this.client = ClientBuilder.newBuilder().build();
            // The root URL is your API starting point, e.g. https://host/api
            this.apiRoot = client.target(rootUrl);
        }
    
        public Response doPostToAccounts(String data)
        {
            try 
            {
                // This is where you execute your POST request
                return apiRoot.path("/Accounts")
                    .request(MediaType.APPLICATION_JSON)
                    .post(Entity.entity(data, MediaType.APPLICATION_JSON));
            } catch (Exception e) {
                throw new IllegalStateException(e);
            }
        }
    
    }
    

    【讨论】:

    • 感谢您的回复。我试过你的解决方案。我收到“服务器重定向太多次(20)”错误。比我搜索它,我发现添加 ClientProperties.FOLLOW_REDIRECTS,false 可能已经解决了问题,但这次我得到 301- 永久移动
    • 您是否将 https://localhost/PasswordVault/api 作为 rootUrl 并将 /Accounts 作为路径传递?通常 301 意味着它期望 / 在末尾。另外:Response 对象将包含有关它将您重定向到何处的信息。
    • 感谢您的警告。正如你所提到的,我错误地复制了 url。更正后,我再次收到 400 Bad request。我尝试了 3 种不同的方法来调用服务。并得到相同的 400 响应。我很确定与邮递员的要求有些不同。我将在我的请求中添加邮递员标头中的额外内容。
    • 请记住,HTTP 400 错误通常意味着:请求正文对于资源不正确,或者内容类型对于正文不正确。
    【解决方案2】:

    一些想法:

    • 用 UTF-8 编码您的请求发布数据:"post data".getBytes(StandardCharsets.UTF_8)
    • 阅读服务器的响应(不仅仅是代码),希望能获得有关问题的更多详细信息 (connection.getErrorStream())
    • 是否缺少授权标头? (API 令牌等)
    • 使用单引号使您的请求数据字符串更具可读性,或使用 JSON 库避免人为错误
    • 在flush()之后也调用OutputStream.close()

    例如

      // handle error code
      if(connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
        // use getErrorStream for non OK statuses (https://stackoverflow.com/questions/613307/read-error-response-body-in-java)
        String errorMessage = "HTTP response code: " + responseCode
            + (responseMessage == null || responseMessage.trim().length() == 0 ? "" : " " + responseMessage);
    
        InputStream errorStream = connection.getErrorStream();
        if(errorStream != null) {
          String errorString = streamToString(connection.getErrorStream());
          if(errorString.length() > MAX_MSG_LENGTH) {
            errorString = errorString.substring(0, Math.min(MAX_MSG_LENGTH, errorString.length())) + "...";
          }
          errorMessage += ", HTTP response data: " + errorString;
        }
    
        throw new RuntimeException(errorMessage);
      }
    
      // handle OK code
      // ...
    

    【讨论】:

    • 我正在从另一个 URL 获取授权令牌。TOken URL 响应有额外的引号。所以这就是问题所在。真可惜。感谢您的帮助。
    • 太好了,很高兴听到!
    【解决方案3】:

    首先,检查邮递员可能发送而您的代码没有发送的请求标头。在发送请求之前,您可能需要在请求中添加一些标头。其次,我强烈建议使用一些 3d 方 Http 客户端库,而不是自己编写 HTTP 请求。一些著名的库是Apache Http clientOK Http client。我个人使用我自己的 Http 客户端,它是 MgntUtils 开源库的一部分。欢迎您也尝试一下。下面是简化的代码,只是为了演示从站点读取一些响应:

        try {
            HttpClient client = new HttpClient();
            client.setConnectionUrl("https://www.yahoo.com/");
            String result = client.sendHttpRequest(HttpMethod.GET);
            System.out.println(result);
        } catch (IOException e) {
            System.out.println(TextUtils.getStacktrace(e, "com.mgnt."));
        }
        
    

    当然,您也可以使用此库发送 POST 请求并设置请求标头并读取文本或二进制响应和响应标头。这是HttpClient class Javadoc 的链接。该库本身以Maven artifactGithub 的形式提供,包括Javadoc 和源代码

    【讨论】:

    • 感谢您的回复。我按照您的建议尝试了 Apache HttpClien。但我仍然收到 400 Bad request response。
    • 所以,检查响应头,你可能会找到错误的原因
    • 另外,如果您使用我的库,如果返回错误代码,它会自动检索 errorStream。因此,您无需额外编码即可获得更多额外信息
    猜你喜欢
    • 2015-06-02
    • 1970-01-01
    • 2021-12-18
    • 2015-04-28
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 2021-12-23
    相关资源
    最近更新 更多