HTTP 400 尝试使用 Java 中的 HttpClient 发送 HTTP Post GraphQL 查询



对外部 GraphQL 服务器进行后查询,该服务器在 Postman Pro 设置中作为预请求脚本工作。

我试图使用 HttpClient 访问外部 GraphQL 服务器。

Maven dependencies pom.xml:

<!-- Apache Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.5</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.2.4</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-cache</artifactId>
<version>4.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.2.5</version>
</dependency>
<!-- Google Code -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>

对预请求脚本进行硬编码,如下所示:

GetDataAsRequest.java

public class GetDataAsRequest {
private static final String GET_DATA_REQUEST_TEMPLATE = 
"query {" 
+ "    viewer {     "
+ "        data(id: "10045701-2017-41a4-33f4-bf8481cf01dc") {" + 
"            id"
+ "            createdDate" 
+ "            lastModifiedDate" 
+ "            abbreviation"
+ "            cityStateRegion" 
+ "        }"
+ "    }"
+ "}";
}
public static String generateQuery() {
return String.format(GET_DATA_REQUEST_TEMPLATE);
}
}

我的控制器:

public class MyController {
private static final String EXTERNAL_API_URL = "https://sample-api.com"
public static void main (String args []) {
// Generate Access Token
String accessToken = OAuth2Client.generateAccessToken();
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(EXTERNAL_API_URL);
StringEntity postBody = new StringEntity(GetDataAsRequest.generateQuery());
postBody.setContentType("application/json");
postRequest.addHeader("Authorization", "Bearer " + accessToken);
postRequest.setEntity(postBody);
HttpResponse response = httpClient.execute(postRequest);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));
String output;
System.out.println("Output from Server .... n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
httpClient.getConnectionManager().shutdown();
} 
catch (MalformedURLException e) {
e.printStackTrace();
} 
catch (IOException e) {
e.printStackTrace();
}
}

尽管当我将OAuthToken和HTTP post查询从stdin(控制台(复制到Postman调用时,相同的OAuthToken和HTTP post查询有效,但是当尝试在Java程序中使用HttpClient模拟相同的调用时,我不断收到HTTP 400:

03:25:30.690 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Get connection for route {s}->https://https://sample-api.com
03:25:30.751 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnectionOperator - Connecting to https://sample-api.com:443
03:25:30.943 [main] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: best-match
03:25:30.950 [main] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context
03:25:30.950 [main] DEBUG org.apache.http.client.protocol.RequestTargetAuthentication - Target auth state: UNCHALLENGED
03:25:30.951 [main] DEBUG org.apache.http.client.protocol.RequestProxyAuthentication - Proxy auth state: UNCHALLENGED
03:25:30.951 [main] DEBUG org.apache.http.impl.client.DefaultHttpClient - Attempt 1 to execute request
03:25:30.951 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnection - Sending request: POST /v1/oauth/token HTTP/1.1
03:25:30.951 [main] DEBUG org.apache.http.wire - >> "POST /v1/oauth/token HTTP/1.1[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "Content-Length: 119[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "Content-Type: application/x-www-form-urlencoded; charset=UTF-8[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "Host: https://sample-api.com[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "Connection: Keep-Alive[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "User-Agent: Apache-HttpClient/4.2.5 (java 1.5)[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.wire - >> "[r][n]"
03:25:30.952 [main] DEBUG org.apache.http.headers - >> POST /v1/oauth/token HTTP/1.1
03:25:30.952 [main] DEBUG org.apache.http.headers - >> Content-Length: 119
03:25:30.952 [main] DEBUG org.apache.http.headers - >> Content-Type: application/x-www-form-urlencoded; charset=UTF-8
03:25:30.952 [main] DEBUG org.apache.http.headers - >> Host: https://sample-api.com
03:25:30.952 [main] DEBUG org.apache.http.headers - >> Connection: Keep-Alive
03:25:30.953 [main] DEBUG org.apache.http.headers - >> User-Agent: Apache-HttpClient/4.2.5 (java 1.5)
03:25:30.953 [main] DEBUG org.apache.http.wire - >> "grant_type=client_credentials&client_id=fghuXeULFBdW4B1dmRY0MhROMRQnlumk&client_secret=MM2banXEq2R1GhRvIQ2d2AKRx0SORvb4"
03:25:31.132 [main] DEBUG org.apache.http.wire - << "HTTP/1.1 200 OK[r][n]"
03:25:31.134 [main] DEBUG org.apache.http.wire - << "X-Application-Context: application:prod[r][n]"
03:25:31.134 [main] DEBUG org.apache.http.wire - << "Content-Type: application/json[r][n]"
03:25:31.134 [main] DEBUG org.apache.http.wire - << "Cache-Control: no-store[r][n]"
03:25:31.134 [main] DEBUG org.apache.http.wire - << "Pragma: no-cache[r][n]"
03:25:31.134 [main] DEBUG org.apache.http.wire - << "Accept-Ranges: bytes[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "X-Cache-Hits: 0[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "X-Timer: S1525774921.421988,VS0,VE41[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Date: Tue, 08 May 2018 10:22:01 GMT[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Content-Length: 325[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Connection: keep-alive[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "X-Sample-APP: sso[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Access-Control-Allow-Headers: Authorization,Content-Type[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Access-Control-Allow-Methods: PUT,POST,OPTIONS,GET,PATCH,DELETE[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "Access-Control-Allow-Origin: *[r][n]"
03:25:31.135 [main] DEBUG org.apache.http.wire - << "[r][n]"
03:25:31.136 [main] DEBUG org.apache.http.impl.conn.DefaultClientConnection - Receiving response: HTTP/1.1 200 OK
03:25:31.136 [main] DEBUG org.apache.http.headers - << HTTP/1.1 200 OK
03:25:31.136 [main] DEBUG org.apache.http.headers - << X-Application-Context: application:prod
03:25:31.136 [main] DEBUG org.apache.http.headers - << Content-Type: application/json
03:25:31.136 [main] DEBUG org.apache.http.headers - << Cache-Control: no-store
03:25:31.136 [main] DEBUG org.apache.http.headers - << Pragma: no-cache
03:25:31.138 [main] DEBUG org.apache.http.headers - << Accept-Ranges: bytes
03:25:31.138 [main] DEBUG org.apache.http.headers - << X-Served-By: cache-sample-las9320
03:25:31.138 [main] DEBUG org.apache.http.headers - << X-Cache-Hits: 0
03:25:31.138 [main] DEBUG org.apache.http.headers - << X-Timer: S1525774921.421988,VS0,VE41
03:25:31.138 [main] DEBUG org.apache.http.headers - << Date: Tue, 08 May 2018 10:22:01 GMT
03:25:31.138 [main] DEBUG org.apache.http.headers - << Content-Length: 325
03:25:31.138 [main] DEBUG org.apache.http.headers - << Connection: keep-alive
03:25:31.138 [main] DEBUG org.apache.http.headers - << X-Sample-APP: sso
03:25:31.138 [main] DEBUG org.apache.http.headers - << Access-Control-Allow-Headers: Authorization,Content-Type
03:25:31.138 [main] DEBUG org.apache.http.headers - << Access-Control-Allow-Methods: PUT,POST,OPTIONS,GET,PATCH,DELETE
03:25:31.138 [main] DEBUG org.apache.http.headers - << Access-Control-Allow-Origin: *
03:25:31.141 [main] DEBUG org.apache.http.impl.client.DefaultHttpClient - Connection can be kept alive indefinitely
03:25:31.147 [main] DEBUG org.apache.http.wire - << "{"access_token":"fkMmGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6bnVsbCwiZGV2aWNlSWQiOm51bGwsImNsaWVudElkIjoiaUxIdVhlVUxGQmRXNEIxZG1SWTBNaFJPTVJRbmxmZUsiLCJhZElkIjpudWxsLCJleHAiOjE1MjU3Nzg1MjEsImlhdCI6MTUyNTc3NDkyMX0.U3gacgf7a8hlwCuCn6yGXc0z6E5Zrwgii3B_77xFlyo","token_type":"Bearer","expires_in":3600,"refresh_token":null,"scope":null}"
03:25:31.147 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Releasing connection org.apache.http.impl.conn.ManagedClientConnectionImpl@2ddc8ecb
03:25:31.147 [main] DEBUG org.apache.http.impl.conn.BasicClientConnectionManager - Connection can be kept alive indefinitely
Exception in thread "main" java.lang.RuntimeException: Failed : HTTP error code : 400

这是否返回 HTTP 400,因为我的请求正文在某些方面是错误的?

有没有更简单的方法可以通过 GraphQL 的 Java 库获取 JSON 响应:

<!-- GraphQL -->
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java</artifactId>
<version>8.0</version>
</dependency>
<dependency>
<groupId>com.graphql-java</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>5.0.0</version>
</dependency>

互联网上的很多例子展示了如何设置和外部 GraphQL 服务器,我需要的是学习如何使用 GraphQL Java 库作为客户端库来解析并从外部服务器获取正确的 GraphQL 响应......

这是从Postman Pro和curl正确返回的,但没有使用HttpClient。

我可能做错了什么?

你控制服务器吗?如果是这样,为什么不在那里放置一个断点并检查哪些失败?如果您不控制服务器,我会说仔细检查您在此处发送的内容与Postman发送的内容之间的差异。

有一件事看起来非常可疑。您正在发送一个声称具有 JSON 正文的 POST,但您发送的字符串是原始的 GraphQL 查询,而不是 JSON。

我可以告诉你将请求正文转换为由 GraphQL over HTTP 规范定义的 JSON 对象,但不知道你的服务器是否真的实现了这个规范,这只是一个猜测。

规范定义为 POST 请求的正确主体是一个具有 3 个字段的 JSON 对象:queryoperationNamevariablesquery字段应包含查询字符串(因此首先将查询字符串化(,operationName包含多个操作(与您的情况无关(时要执行的操作的名称,variables包含将变量作为键值对的 JSON 对象(目前不相关(。

意思是,在你的情况下,身体应该看起来像:

{
query: "{
viewer {
data(id: "10045701-2017-41a4-33f4-bf8481cf01dc") {
id
createdDate
lastModifiedDate
abbreviation
cityStateRegion
}
}
}"
}

要将此字符串放入 Java 代码中,所有这些都需要额外的转义级别,但我希望您的 IDE 能够解决这个问题。另请注意换行符很重要。如果由于任何原因丢失了它们,则必须在所选字段之间放置逗号,以使查询保持有效。

最新更新