到 Web 服务的 SOAP 消息 - HTTP 响应代码:URL 的 403
Posted
技术标签:
【中文标题】到 Web 服务的 SOAP 消息 - HTTP 响应代码:URL 的 403【英文标题】:SOAP message to webservice - HTTP response code: 403 for URL 【发布时间】:2018-01-06 16:21:44 【问题描述】:我尝试将XML
文件中的SOAP
消息发送到网络服务,然后获取二进制输出并对其进行解码。 Endpoint 使用HTTPS
协议,所以我在代码中使用TrustManager
以避免PKIX
问题。你可以在这里看到我的代码:
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.X509Certificate;
public class Main
public static void sendSoapRequest() throws Exception
String SOAPUrl = "URL HERE";
String xmlFile2Send = ".\\src\\request.xml";
String responseFileName = ".\\src\\response.xml";
String inputLine;
TrustManager[] trustAllCerts = new TrustManager[] new X509TrustManager()
public java.security.cert.X509Certificate[] getAcceptedIssuers() return null;
public void checkClientTrusted(X509Certificate[] certs, String authType)
public void checkServerTrusted(X509Certificate[] certs, String authType)
;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier()
public boolean verify(String hostname, SSLSession session) return true;
;
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
// Create the connection with http
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
FileInputStream fin = new FileInputStream(xmlFile2Send);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
copy(fin, bout);
fin.close();
byte[] b = bout.toByteArray();
StringBuffer buf=new StringBuffer();
String s=new String(b);
b=s.getBytes();
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length", String.valueOf(b.length));
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction", "");
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
OutputStream out = httpConn.getOutputStream();
out.write(b);
out.close();
// Read the response.
httpConn.connect();
System.out.println("http connection status :"+ httpConn.getResponseMessage());
InputStreamReader isr = new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
FileOutputStream fos=new FileOutputStream(responseFileName);
copy(httpConn.getInputStream(),fos);
in.close();
public static void copy(InputStream in, OutputStream out) throws IOException
synchronized (in)
synchronized (out)
byte[] buffer = new byte[256];
while (true)
int bytesRead = in.read(buffer);
if (bytesRead == -1)
break;
out.write(buffer, 0, bytesRead);
public static void main(String args[]) throws Exception
sendSoapRequest();
执行此操作时出现以下错误代码。
线程“main”java.io.IOException 中的异常:服务器返回 HTTP 响应代码:URL 403
【问题讨论】:
您应该提供凭据以获得访问权限。用于基本身份验证的 base64 中带有登录名/密码的身份验证标头,最简单的变体,但它取决于服务器端。您应该提供所需的服务器。 @user1516873 : 无需在此服务器上进行身份验证。 403-forbidden 表示请求已经到达服务器并且是有效的,但是服务器拒绝访问所请求的资源。总而言之,SSL 连接正常,因此您调用了错误的端点或 SOAP 标头中缺少凭据。 @pedrofb :我明白了,但是当我在带有 SoapUI 的 SOAP 请求中使用 XML 文件的内容时,我会从同一个端点得到响应。 如果内容相同,则检查并比较实际发送 SOAPUI 的标头和您的连接。有可能是服务器检测到了一些不正确,将其视为 403 【参考方案1】:你的实现没问题,实际上问题与你的Content-Type
标头有关。
值text/xml; charset=utf-8
是SOAP 1.1 的默认Content-Type
,它可能不是您的版本。 SOAP 1.2 expects a header of type application/soap+xml; charset=utf-8
,因此将您的代码行更改为下面的代码会使其正常工作:
httpConn.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8");
在 SoapUI 中,可以检查调用请求的标头并转到窗口底部的 Headers 选项卡:
然后,您可以比较您的应用程序配置和 SoapUI 配置之间的差异。
【讨论】:
我在 SoapUI 中找不到任何标题,我也得到与此Content-Type
完全相同的错误。
标头在响应端,而不是在请求中。提出请求并在那里检查。
响应端是application/timestamp-reply
。
您可以共享端点吗?或者至少是 GitHub 的服务项目?很难猜测您的实施的具体情况。
抱歉,只能从本地网络访问。【参考方案2】:
403 错误可能与您发送到服务器的soap 请求标头有关。 所有有效的主机都将允许您的 Java 应用程序信任 URL 的 SSL 证书。 检查您的服务器是否需要带有用户名/密码的soap标头。如果您有权访问此服务器,则可以通过 Web 服务器日志检查您的请求失败的位置。错误代码指向缺少 Soap 标头,尤其是带有用户名和密码的 Soap 标头
【讨论】:
不需要用户名/密码,当前SoapUI请求中没有设置。【参考方案3】:想知道您的 SOAP 请求是否在 SAML 等标头中包含任何类型的身份验证信息。一种选择是,在上面的代码中,您读取文件并将数据发送到服务器,而不是将其发送到服务器,而是将其转储到另一个文件。转储该字节输出流。然后从该文件复制文本并将其放入 SOAP UI 并尝试运行它。那样有用吗?
【讨论】:
为什么制作另一个内容相同的文件更好? 特别是在您的 SOAP 请求包含 SAML 或其他一些二进制数据的情况下。那是看它是否在文件 IO 期间被损坏。您的代码包含以下一小部分:byte[] b = bout.toByteArray(); StringBuffer buf=new StringBuffer(); String s=new String(b); b=s.getBytes();
,您将在其中将数据转换为字符串并返回字节。是否有特定的需要这样做?
正如@pedrofb 所建议的,我之前从代码中删除了这些行。
哦,好的。您是否能够捕获从 SOAP UI 发送的标头与从您的代码发送的标头。那些也一样。
是的,我向 Requestbin 发送了请求,但正文为空。我的 Java 代码有问题吗?【参考方案4】:
在我们之前遇到过类似的情况,只要尝试TrustManager
没有按预期工作,我们设法通过将证书从服务器安装到 JVM 的密钥库(JVM 用于运行应用)。您可以在几篇文章中找到有关如何操作的更多信息,例如
How to import a .cer certificate into a java keystore?
我知道这是一种强制 JVM 接受 SSL 证书的尝试,而且这个功能在应用程序上下文中会更好,但只要我们构建一个在特定应用程序服务器中运行的 Web 应用程序,实现的解决方案已被接受。
【讨论】:
以上是关于到 Web 服务的 SOAP 消息 - HTTP 响应代码:URL 的 403的主要内容,如果未能解决你的问题,请参考以下文章
wininet api 将文件发送到 http web 服务
如何将 WS-Addressing 字段添加到 SOAP 消息