【问题标题】:401 for PostRequest with HttpURLConnection使用 HttpURLConnection 发布请求的 401
【发布时间】:2021-03-18 08:23:52
【问题描述】:

更新 我的问题原来是由于一些超类的怪异。但是,此示例中的 urlEncode 是错误的。在这种情况下,它也是不必要的。如果需要,应该通过每个键和值来完成,而不需要编码 & 或 =。 除此之外,这段代码是正确的。


下面的 (scala) 代码失败,因为服务器似乎没有收到正文。 服务器日志上的警告是:

警告 *** OAuthTokenProcessor 捕获了带有消息 OAuthProblemException{error='invalid_request', description='Missing grant_type parameter value', uri='null', state='null', scope='null', redirectUri= 的 OAuthRequestProblemException 'null',responseStatus=0,参数={}}

我确信参数是正确的。网址正确,标题正确 (这个调用已经在 Postman 和 Python 中有效)

非常感谢任何提示!

private def doPostRequest(): Unit ={
  try {

    val connectionforPost = (new URL(url)).openConnection.asInstanceOf[HttpURLConnection]


    val params = "grant_type=password&client_id=xxxx&client_secret=seccret&username=admin&password=xxxx"
    val encodedString = URLEncoder.encode(params,"UTF-8")
    import java.nio.charset.StandardCharsets
    val postData = encodedString.getBytes(StandardCharsets.UTF_8)

    val contentlength = Integer.toString(encodedString.length)

    connectionforPost.setConnectTimeout(50000)
    connectionforPost.setReadTimeout(50000)
    connectionforPost.setRequestMethod("POST")
    connectionforPost.setDoOutput(true)
    connectionforPost.setDoInput(true)
    connectionforPost.setInstanceFollowRedirects(false)
    connectionforPost.setRequestProperty("User-agent", "test bot")
    connectionforPost.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
    connectionforPost.setRequestProperty("Accept", "*/*")
    connectionforPost.setRequestProperty("Connection", "keep-alive")
    connectionforPost.setRequestProperty("Content-Length", contentlength)
    connectionforPost.setRequestProperty("Accept-Encoding", "gzip, deflate")
    connectionforPost.setUseCaches(false)


    import java.io.DataOutputStream

    val wr = new DataOutputStream(connectionforPost.getOutputStream)
    wr.write(postData)
    if (wr != null) wr.close()



  } catch{
    case e:Exception => logger.error(e.getMessage,e)
      throw e
  }
}

【问题讨论】:

  • encodedString 的值是多少?
  • grant_type%3Dpassword%26client_id%3Dxxxxx%26client_secret%3Dsecret%26username%3Dadmin%26password%3Dxxxx
  • 您已经对 '=' 和 '&' 字符进行了编码。如果它们出现在您传递的值中,则需要对其进行编码,但不应将它们编码在帖子的正文中
  • 试着看看工作请求和不工作请求之间的确切区别是什么。使用工具在低级别记录请求。
  • 有一个选项可以在邮递员中查看整个 curl 请求。它将帮助您找到差异。

标签: java scala httpurlconnection


【解决方案1】:

服务器似乎抱怨您没有登录。您收到身份验证问题异常。它通常的工作方式是您向服务器发送请求以使用用户名和密码登录。如果服务器对您进行身份验证(将您的用户名和密码识别为有效的),它会向您发送一个响应,其中包含标头中的身份验证令牌。您可能会在成功登录的响应中看到这 2 个标题:

 access-control-expose-headers=[Authorization], Authorization=[Bearer ....]

这意味着在您的所有后续请求中,您将需要添加一个标头“授权”,该标头将包含值“Bearer ....”。然后服务器会将此请求识别为来自经过身份验证的用户。 另外,我建议您可以使用 3d 方 HTTP 客户端。一些知名客户是Appache HTTP clientOK HTTP client。我使用自己编写的 Http 客户端。它也可作为 MgntUtils 开源库的一部分使用。这是Maven artifacts 的链接,它也可以在Github 上找到,带有源代码和JavaDoc。这是HttpClient 的javadoc 页面。以下是有关如何获取和使用令牌的代码示例:

        try {
        HttpClient loginClient = new HttpClient();
        loginClient.setConnectionUrl("http://your_url/login");
        loginClient.setRequestProperty("accept", "application/json;charset=UTF-8");
        loginClient.setContentType("application/json");
        String result = loginClient.sendHttpRequest(HttpMethod.POST, "{ \"username\": \"your_user_name\", \"password\": \"Your_password\"}");
        System.out.println(result);
        System.out.println("HTTP " + loginClient.getLastResponseCode() + " " + loginClient.getLastResponseMessage());
        System.out.println("Response headers: " + loginClient.getLastResponseHeaders());
        String accessControlExposeHeader = loginClient.getLastResponseHeader("access-control-expose-headers").get(0);
        String accessKey = loginClient.getLastResponseHeader(accessControlExposeHeader).get(0);
        HttpClient workingClient = new HttpClient();
        workingClient.setRequestProperty("accept", "application/json;charset=UTF-8");
        workingClient.setContentType("application/json");
        workingClient.setRequestProperty(accessControlExposeHeader, accessKey);
        workingClient.setConnectionUrl("http://yourUrl/yourPath");
        System.out.println(workingClient.sendHttpRequest(HttpMethod.GET));
    } catch (IOException e) {
        System.out.println(TextUtils.getStacktrace(e));
    }

【讨论】:

  • 谢谢!正如更新中的注释,我的核心问题是由于一些与问题中的代码无关的奇怪的超类进程。即便如此,这个答案完全是主题并且很好地解释了
猜你喜欢
  • 1970-01-01
  • 2016-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多