跨域问题曲折探索背后的一个小小的插曲:header is present on the requested resource错误
经过漫长的半天的探索,终于见到了胜利的曙光。关于这场神奇的探索之旅,有兴趣的朋友可以移步到这篇文章《平凡的跨域问题,竟暗藏波澜:一场意想不到的曲折探索》阅读。
最后,为了验证Access-Control-Expose-Headers这个头的设置不是必须的,差点使得前面的探索前功尽弃,神经已经紧绷,怕这次错误推翻前面的推论。若果真如此,会有一个更大的困惑在前面等着我,使我无法再前进半步。
事情是这样子的,另外一个同事,也在研究这个跨域的问题,因为,看似非常简单的一个跨域问题,却始终不得解决,代码中有一段代码被他注释掉了:一段使用设置跨域请求头的代码。而我,起初并不知道这一段代码被注释了。
结果就是,当我把c.Header("Access-Control-Expose-Headers", "*")
这个去掉之后,再部署到服务器上,就报错了:Access to XMLHttpRequest at 'https://9r3122298l.zicp.fun/dreame-mall/api/v1/user/search-history' from origin 'https://www.google.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
这个报错和前面跨域的报错是不一样的。
域名的限制没有放开,就会报这样的错误:Access to XMLHttpRequest at 'https://9r3122298l.zicp.fun/dreame-mall/api/v1/user/search-history' from origin 'https://www.baidu.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains the invalid value 'baidu.com'。比如,这样的设置c.Header("Access-Control-Allow-Origin", "baidu.com")。
Header的限制没有放开,会报这样的错误:Access to XMLHttpRequest at 'https://9r3122298l.zicp.fun/dreame-mall/api/v1/user/search-history' from origin 'https://www.baidu.com' has been blocked by CORS policy: Request header field dreame-api-timestamp is not allowed by Access-Control-Allow-Headers in preflight response.比如,我们请求中有dreame-api-timestamp这个Header,但是,c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id,Referer,User-Agent")这个设置没有使用“*”这中通配符,也没有包含“dreame-api-timestamp”这个头,就会报这样的错误。
所以,最上面No 'Access-Control-Allow-Origin' header is present on the requested resource.这个报错着实把我已经紧张的神经再度搞得神经质。一是,担心前面的探索依然存在问题,但是,细细想来,并没有道理。二是,从这个错误看不出来是哪个设置有问题。
幸运的是,没有经历太多的波折,最终,发现是跨域的中间件并没有使用导致的这个错误。只要把文章开头提到的那个注释放开就行了。
本文的开头提到,是因为验证Access-Control-Expose-Headers这个头的设置不是必须的,我们先看一下,这个头的含义。我在网络上找了一下其定义:如果服务器希望在跨域请求中允许前端访问其他的自定义响应头,就需要使用 Access-Control-Expose-Headers
头来明确指定这些额外的头信息。于是乎,按照这个定义,我把跨域的设置做了一些改造,把自定义的两个头放在这个设置中。
func Cors() gin.HandlerFunc {return func(c *gin.Context) {method := c.Request.Method// origin := c.Request.Header.Get("Origin")c.Header("Access-Control-Allow-Origin", "*")c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id,Referer,User-Agent")c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT")c.Header("Access-Control-Expose-Headers", "dreame-api-timestamp,dreame-api-sign")c.Header("Access-Control-Allow-Credentials", "true")if method == "OPTIONS" {c.AbortWithStatus(http.StatusNoContent)}// 处理请求c.Next()}
}
按照这个设置,并不能生效,依然会报跨域错误。
但是,把自定义头放在这个设置中Access-Control-Allow-Headers,就不会报跨域的错误,即c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id,Referer,User-Agent,dreame-api-timestamp,dreame-api-sign")或者c.Header("Access-Control-Allow-Headers", "*")设置就不会跨域的错误。
所以,Access-Control-Expose-Headers这个设置到底是做什么用的?截至发稿前,我并没有找到这个设置的具体作用。哪位大神知道的,不妨在留言区给指点一二,不胜感激。