在与不同域通信时使用 POST 获取 400 错误请求错误
Posted
技术标签:
【中文标题】在与不同域通信时使用 POST 获取 400 错误请求错误【英文标题】:Getting 400 bad request error using POST while communicating to different domain 【发布时间】:2015-12-25 12:32:40 【问题描述】:我们有两个用于 UI 和服务器的项目,它们都在不同的域上运行。对于 UI,我们使用 Angular JS,对于服务器端,我们使用 Spring 并向客户端提供 JSON 响应。由于 CORS 问题,我们无法与服务器通信。我们用谷歌搜索并尝试了不同的解决方案。我们找到了以下链接。
https://htet101.wordpress.com/2014/01/22/cors-with-angularjs-and-spring-rest/
我们做了链接中提到的任何事情。它适用于 GET 请求,但不适用于 POST 请求。当我们执行 POST 请求时,我们会收到 400 Bad Request。请查看以下详细信息以获取更多信息。
-
远程地址:
IP:8080
请求网址:
http://IP:8080/controller/addLogin
请求方法:
发布
状态码:
400 错误请求
响应标头:HTTP/1.1 400 错误请求服务器:Apache-Coyote/1.1 访问控制允许来源:* 访问控制允许方法:POST, 获取,选项,删除访问控制最大年龄:3600 Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, 接受 Content-Type: text/html;charset=utf-8 Content-Language: en 内容长度:1113 日期:2015 年 9 月 28 日星期一 09:33:21 GMT 连接: 关闭
请求标头:POST /controller/addLogin HTTP/1.1 主机: 192.168.5.131:8080 连接:keep-alive 内容长度:41 编译指示:无缓存缓存控制:无缓存接受:应用程序/json,文本/纯文本, / 来源: localhost:1337 用户代理: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 Content-Type: 应用程序/json;charset=UTF-8 引用: localhost:1337/login.html 接受编码:gzip,放气 接受语言:en-US,en;q=0.8
得到这个之后,我们在客户端添加了以下行,正如我们在 stacloverflow 中的一些解决方案中看到的那样。但错误仍然相同。
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.headers.common['Access-Control-Allow-Credentials'] = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
$httpProvider.defaults.headers.post['Content-type'] = "application/json";
请帮助我们解决这个问题。
更新问题:
我们做了下面答案中提到的确切更改。然后我们得到了像
这样的异常 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'corsFilter' is defined for enabling cors.
为了解决这个问题,我们创建了 bean
<bean id="corsFilter" class="com.prototype.helper.SimpleCORSFilter" />
在 root-context.xml 文件中。但是我们仍然没有运气,我们仍然收到 400 个错误请求,例如
POST http://IP 地址:8080/controller/addLogin 400(错误请求)。
下面是我们所做的过滤器类和 web.xml 配置:
public class SimpleCORSFilter extends OncePerRequestFilter
// private Set<String> whitelist = Sets.newHashSet("[AllowedOrigin1]", "[AllowedOrigin2]");
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException
String originHeaderFromClient = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", originHeaderFromClient);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
filterChain.doFilter(request, response);
web.xml:
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
【问题讨论】:
【参考方案1】:如果您在浏览器的开发人员选项中检查网络选项卡,您可能会看到浏览器在发出 POST 调用之前正在对服务器进行 OPTIONS 调用。
默认情况下,Spring 的 DispatcherServlet 会阻止 OPTIONS 调用进入您的应用程序。意思是,OPTIONS 调用不会通过。您的浏览器认为您尝试访问的服务器不支持 CORS,因此阻止调用通过。
我们实现了一个过滤器,并在 web.xml 中使用DelegatingFilterProxy
连接它,如下所示:
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在过滤器的doFilter
方法中,做了以下操作:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
String originHeaderFromClient = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", <<acceptedOrigins>>;
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Content-Type");
chain.doFilter(request, response);
这样,所有调用都将获得Access-Control-Allow-Origin
标头,而与GET/POST 无关。而且它还可以让控制器保持 CORS 标头特定设置的清洁(如果您有多个控制器,这会很痛苦)。
【讨论】:
感谢您的回答。我们按照您的建议进行了更改,但仍然无法正常工作。我们通过代码更改更新了问题。 你确定过滤器被调用了吗?您的根上下文是如何加载的?您是否从客户端获取原始标头?理想情况下,您不应该在您的来源中设置客户端的 IP。您应该定义您接受来自哪些来源的请求。 是的过滤器正在被调用。因为当我们在调试模式下运行应用程序时,它会首先进入过滤器。正在使用 web.xml 文件中的 context-param 加载根上下文。从客户端获取原始标头为IPAddress:1337 并在服务器端设置相同,如下所示 String originHeaderFromClient = request.getHeader("Origin"); response.setHeader("Access-Control-Allow-Origin", originHeaderFromClient);我们在客户端使用的代码与下面的链接相同。metabroadcast.com/blog/…以上是关于在与不同域通信时使用 POST 获取 400 错误请求错误的主要内容,如果未能解决你的问题,请参考以下文章