gin解决跨域问题

背景

前端框架:vue.js,是网上别人已经封装好的模板

后台web框架:gin

后台限制请求方式只能是post,所有接口已经测试通过。前端调试始终提示404.日志打印前端的请求方式是options,而不是post。

此时将后台的请求方式由post修改为options,返回成功。

说明问题点就在请求method这里。但是前端明显有设置method为post,到了发送请求的时候自动变成了options

关键

前端在header里面有自定义字段,那么浏览器会首先发送一个options请求,如果请求通过,才会继续发送正式的post请求。

 

解决

后台使用gin自带的解决跨域问题的cors中间件,但是前端继续报错,如下:

Request header field system is not allowed by Access-Control-Allow-Headers in preflight response.

后来前端修改了别人模板里的header信息(这里所谓的修改是前端没有在header里面自定义参数,补充于2018-10-10 15:01),再次访问ok。

========================================分界线=====================================================

抱歉,如果你之前看了这个文章,那我可能有点误导你了。这个跨域问题我是今天上午才彻底解决。

必须严肃对待这个问题。

首先看下为什么会有跨域的问题,需要,如果你无法,那我等以后哪天有空了再翻译吧。参考链接:跨域

关键点如下:

浏览器分两种请求。简单请求的话就是按照vue框架给你封装的,直接Post简单body不修改它的header。如果修改了header那就是复杂请求。得需要考虑跨域问题。解决跨域的是先发一次options请求,获取allowheader,允许跨域之后才会再发真正的Post请求。(这段话是一位大佬发给我的)

这次这个问题是我需要前端在header里面自定义Token给我,就属于复杂请求了,所以就一定会有跨域问题的发生。

网上说的办法不是不行,都可以解决。举个例子,比如这个大佬的文章:

大佬文章:gin跨域

一般中间件都是在所有请求之前绑定的,大佬这篇文章在中间件里面放行了options请求,我也照做了,但是此时前端调用接口或者自己postman模拟的时候只会返回一个200, options request! 的结果,这显然不是页面需要的数据。以大佬的文章来说,我应该在options request!替换为每次响应的结果而不仅仅是options request这么一句话。因为前端不仅仅需要这个状态码,还需要他每次请求以后服务器响应的结果。那么问题来了,这个中间件是在所有请求之前绑定,这时候都还没有调用接口,哪里有数据返回给前端?

解决关键:AbortWithStatus()

在遇到options请求以后,不需要像大佬文章里的那样返回结果给前端,而应该是调用

c.AbortWithStatus(http.StatusNoContent)

AbortWithStatus()会调用Abort()方法,源码如下,我怕自己翻译会不太准确。

// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
// Let's say you have an authorization middleware that validates that the current request is authorized.
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
// for this request are not called.
func (c *Context) Abort() {
	c.index = abortIndex
}

// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
func (c *Context) AbortWithStatus(code int) {
	c.Status(code)
	c.Writer.WriteHeaderNow()
	c.Abort()
}

回到刚刚的话题,我在调用c.AbortWithStatus()的时候传入的是204,其实个人感觉只要是2开头的状态码,但不要是200都行。等我有空再研究研究

以后postman模拟请求为options的时候,这个请求会暂停,等待用户的下一次post请求来触发接口。前端无需再发送第二次请求即可。

希望对你有帮助。

// 处理跨域请求,支持options访问
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method

		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token")
		c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
		c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		c.Header("Access-Control-Allow-Credentials", "true")

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		// 处理请求
		c.Next()
	}
}

 

你可能感兴趣的:(go,后台)