如何通过JavaScript访问SOAP服务?解决Edge跨域OPTIONS请求异常
问题分析
你遇到的问题是跨域资源共享(CORS)预检请求未被后端处理:
- Edge等现代浏览器在发送跨域的非简单请求(比如
Content-Type为text/xml的POST请求)时,会先发送一个OPTIONS预检请求,询问服务器是否允许该跨域请求。 - 你的Java后端没有处理OPTIONS方法,所以返回空响应,导致前端出现
ERR_EMPTY_RESPONSE错误。 - IE能正常运行是因为它的CORS实现逻辑和现代浏览器不同,未触发预检请求,或是使用兼容模式绕过了预检。
解决方案
后端(Java)处理OPTIONS请求
核心是让后端接收并响应OPTIONS请求,返回正确的CORS头,以下是几种实现方式:
方式1:添加CORS过滤器(通用方案)
创建一个Servlet过滤器,专门处理OPTIONS请求并返回允许的跨域头:
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CorsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; HttpServletRequest httpRequest = (HttpServletRequest) request; // 允许的前端域名,可根据实际设置,用*代表允许所有 httpResponse.setHeader("Access-Control-Allow-Origin", "http://你的前端地址"); // 允许的请求方法 httpResponse.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); // 允许的请求头 httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 预检请求的缓存时长(秒) httpResponse.setHeader("Access-Control-Max-Age", "3600"); // 处理OPTIONS请求,直接返回200状态码 if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) { httpResponse.setStatus(HttpServletResponse.SC_OK); return; } chain.doFilter(request, response); } @Override public void destroy() {} }
在web.xml中配置该过滤器,绑定到你的SOAP服务路径:
<filter> <filter-name>CorsFilter</filter-name> <filter-class>com.yourpackage.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>CorsFilter</filter-name> <url-pattern>/ts</url-pattern> <!-- 对应你的SOAP服务路径 --> </filter-mapping>
方式2:JAX-WS端点直接处理OPTIONS
如果你的SOAP服务基于JAX-WS实现,可在端点类中直接添加OPTIONS方法的处理:
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.OPTIONS; import javax.ws.rs.Path; import javax.ws.rs.core.Context; @Path("/ts") public class YourSoapEndpoint { @OPTIONS public void handleOptions(@Context HttpServletRequest request, @Context HttpServletResponse response) { response.setHeader("Access-Control-Allow-Origin", "http://你的前端地址"); response.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "Content-Type"); response.setStatus(HttpServletResponse.SC_OK); } // 你的SOAP服务业务方法 // ... }
前端优化建议
- 配置正确的
SOAPAction头:取消注释代码中的xmlhttp.setRequestHeader('SOAPAction', 'http://ts.ch01/getAsTimeElapsed');(值需匹配你的SOAP服务实际的SOAPAction,通常是命名空间加方法名)。 - 添加错误处理逻辑,便于排查问题:
xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) { if (xmlhttp.status == 200) { alert(xmlhttp.responseText); } else { console.error('请求失败,状态码:', xmlhttp.status); alert('请求失败,请查看控制台日志'); } } }
内容的提问来源于stack exchange,提问作者rama rao
相关产品推荐
相关产品推荐

