Angular 应用程序仅在 chrome 中出现 CORS 错误

Posted

技术标签:

【中文标题】Angular 应用程序仅在 chrome 中出现 CORS 错误【英文标题】:Angular app gets CORS error only in chrome 【发布时间】:2021-11-16 14:28:57 【问题描述】:

在我的 Angular 应用程序(带有远程服务器的本地主机应用程序)上,我只在 chrome 中收到 CORS 错误,在 Firefox 中,它运行良好。 一旦它在两者上都有效,但突然停止在 Chrome 上工作,我猜它与一种更新有关(我猜是 chrome??) Ofcorse,将应用上传到生产服务器在两种浏览器上都可以工作。

我的服务器端代码使用 Java (Servlets),我的 CORSFilter 如下所示:

public class CORSFilter implements Filter 
 
    /**
     * Default constructor.
     */
    public CORSFilter() 
        
    
 
    /**
     * @see Filter#destroy()
     */
    public void destroy() 
        
    
 
    private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");
    
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) 
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            // Access-Control-Allow-Origin
            String origin = request.getHeader("Origin");
            LoggingService.writeToLog("call from origin: "+origin+", will be accepted? "+(allowedOrigins.contains(origin)||origin!=null), LogModule.WebAPI, LogLevel.Debug);
            
            response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
            response.setHeader("Vary", "Origin");
            
            
            // Access-Control-Allow-Credentials
            response.setHeader("Access-Control-Allow-Credentials", "true");

            // Access-Control-Allow-Methods
            response.setHeader("Access-Control-Allow-Methods", "POST,HEAD, PUT, GET, OPTIONS, DELETE");
                       
            // Access-Control-Allow-Headers
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-TOKEN");
            if (request.getMethod().equals("OPTIONS")) 
                response.setStatus(HttpServletResponse.SC_ACCEPTED);
                return;
            
     
        

        chain.doFilter(req, res);
        
    

    

关于如何使其在 Chrome 中也能正常工作的任何想法?

【问题讨论】:

你得到了什么 cors 错误?,它可能是几个,过滤器看起来很好 此 set-cookie 未指定 samesite 属性,默认为 samesite=lax 并被阻止 我将它添加到服务器代码但没有帮助 这与 cors 无关,与服务器 cookie 配置无关,您必须检查应用程序的实际请求链以正确设置 cookie,也可能 cookie 不是来自后端而不是前端应用程序 嗯,我同意你的看法,这是 cookie 的问题,但它与 CORS 政策有关。我附上了我所做的解决方案 【参考方案1】:

该问题与上次更改 SameSite cookie 的 Chrome 浏览器 CORS 策略有关。 对我来说,因为我想启用 CORS,所以我必须添加 SameSite=None 参数。 这是更新的代码。 这是帮助我验证需要做什么的帖子: Set cookies for cross origin requests

请注意,如果您确实需要启用 CORS 选项,则此代码非常有用。这是一个重大决定。

public class CORSFilter implements Filter 
 

 
    private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");
    
    private final String SESSION_COOKIE_NAME = "JSESSIONID";
    private final String SESSION_PATH_ATTRIBUTE = ";Path=";
    private final String ROOT_CONTEXT = "/";
    private final String SAME_SITE_ATTRIBUTE_VALUES = ";HttpOnly;SameSite=None;Secure";
 
    
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) 
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;

            // Access-Control-Allow-Origin
            String origin = request.getHeader("Origin");
            LoggingService.writeToLog("call from origin: "+origin+", will be accepted? "+(allowedOrigins.contains(origin)||origin!=null), LogModule.WebAPI, LogLevel.Debug);
            
            response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
            response.setHeader("Vary", "Origin");
            String requestUrl = request.getRequestURL().toString();
            
            // Access-Control-Max-Age
            //response.setHeader("Access-Control-Max-Age", "3600");

            // Access-Control-Allow-Credentials
            response.setHeader("Access-Control-Allow-Credentials", "true");

            // Access-Control-Allow-Methods
            response.setHeader("Access-Control-Allow-Methods", "POST,HEAD, PUT, GET, OPTIONS, DELETE");
            
            /*
            This the code that i added to the code to use SameSite=None Cookie
            */
            boolean isResourceRequest = requestUrl != null ? StringUtils.isNoneBlank(allowedOrigins.stream().filter(s -> requestUrl.contains(s)).findFirst().orElse(null)) : null;
            if (!isResourceRequest) 
                Cookie[] cookies = ((HttpServletRequest) request).getCookies();
                if (cookies != null && cookies.length > 0) 
                    List<Cookie> cookieList = Arrays.asList(cookies);
                    Cookie sessionCookie = cookieList.stream().filter(cookie -> SESSION_COOKIE_NAME.equals(cookie.getName())).findFirst().orElse(null);
                    if (sessionCookie != null) 
                        String contextPath = request.getServletContext() != null && StringUtils.isNotBlank(request.getServletContext().getContextPath()) ? request.getServletContext().getContextPath() : ROOT_CONTEXT;
                        response.setHeader("Set-Cookie", sessionCookie.getName() + "=" + sessionCookie.getValue() + SESSION_PATH_ATTRIBUTE + contextPath + SAME_SITE_ATTRIBUTE_VALUES);
                    
                
            
            
           /*
            End of new code
           */
            
            // Access-Control-Allow-Headers
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-TOKEN");
            if (request.getMethod().equals("OPTIONS")) 
                response.setStatus(HttpServletResponse.SC_ACCEPTED);
                return;
            
     
        

        chain.doFilter(req, res);
        
    
    
 
 

【讨论】:

以上是关于Angular 应用程序仅在 chrome 中出现 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

Angular 将文件保存为 csv 导致网络错误仅在 Chrome 上

PUT 请求仅在 Chrome 或 Opera 中生成 SPDY 协议错误?

Angular 8 急切加载模块(包括应用程序模块)不会出现在 chrome 开发工具中

移动 Safari/Chrome 上的 Angular 应用程序中出现严重的键盘延迟

仅在 Google Chrome 中出现“无效的表单控件”

仅在第一次加载 Angular 网页时使用 Safari 接收 401 状态