Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于跨域自定义header的问题 #422

Closed
jackluo2012 opened this issue Jan 28, 2021 · 11 comments
Closed

关于跨域自定义header的问题 #422

jackluo2012 opened this issue Jan 28, 2021 · 11 comments
Labels
area/documentation Improvements or additions to documentation

Comments

@jackluo2012
Copy link

场景说明:

在前后端分离的开发中,前端是单独部署的,可能是一个www.aaa.com的域名,而用go-zero的后端程序,可能部署在了www.bbb.com,这种方式在处理用户登陆的时候,基本上用的是jwt,用到jwt 基本上就要用到自定义header 的问题,比如header 里面可能会传Authorization这样的header头,但是Authorization这个又不是标准的响应头具体可以参考:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
然后看了一下官方的关于跨域的请求方式

package rest

import "net/http"

const (
	allowOrigin  = "Access-Control-Allow-Origin"
	allOrigins   = "*"
	allowMethods = "Access-Control-Allow-Methods"
	allowHeaders = "Access-Control-Allow-Headers"
	headers      = "Content-Type, Content-Length, Origin"
	methods      = "GET, HEAD, POST, PATCH, PUT, DELETE"
)

// CorsHandler handles cross domain OPTIONS requests.
// At most one origin can be specified, other origins are ignored if given.
func CorsHandler(origins ...string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if len(origins) > 0 {
			w.Header().Set(allowOrigin, origins[0])
		} else {
			w.Header().Set(allowOrigin, allOrigins)
		}
		w.Header().Set(allowMethods, methods)
		w.Header().Set(allowHeaders, headers)
		w.WriteHeader(http.StatusNoContent)
	})
}

这个写得很简单,属于 简单跨域请求,满足不了,

前后端分离的复杂跨域请求(因为是要做自定义header)

@sliveryou
Copy link

sliveryou commented Jan 29, 2021

为了解决这个问题,我是重新设计了跨域的中间件:

// api/internal/middleware/corsmiddleware.go

package middleware

import "net/http"

// CorsMiddleware 跨域请求处理中间件
type CorsMiddleware struct {
}

// NewCorsMiddleware 新建跨域请求处理中间件
func NewCorsMiddleware() *CorsMiddleware {
	return &CorsMiddleware{}
}

// Handle 跨域请求处理
func (m *CorsMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		setHeader(w)

		// 放行所有 OPTIONS 方法
		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
			return
		}

		// 处理请求
		next(w, r)
	}
}

// Handler 跨域请求处理器
func (m *CorsMiddleware) Handler() http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		setHeader(w)

		if r.Method == "OPTIONS" {
			w.WriteHeader(http.StatusNoContent)
		} else {
			w.WriteHeader(http.StatusNotFound)
		}
	})
}

// setHeader 设置响应头
func setHeader(w http.ResponseWriter) {
	w.Header().Set("Access-Control-Allow-Origin", "*")
	w.Header().Set("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, Authorization, AccessToken, Token")
	w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
	w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
	w.Header().Set("Access-Control-Allow-Credentials", "true")
}

在main函数中:

// api/api.go

func main() {
        ......
	server := rest.MustNewServer(c.RestConf,
		rest.WithNotAllowedHandler(middleware.NewCorsMiddleware().Handler()))
	defer server.Stop()
	server.Use(middleware.NewCorsMiddleware().Handle)
        ......
}

重点是要分别注册MethodNotAllowed的情况下和MethodAlowed情况下的跨域处理。

@kevwan
Copy link
Contributor

kevwan commented Jan 30, 2021

我觉得吧,跨域这事应该在nginx上做的

@jackluo2012
Copy link
Author

@sliveryou 利害

@yuhai-yang
Copy link

管用,很强

@kevwan kevwan added the area/documentation Improvements or additions to documentation label Aug 16, 2021
@fangxh2013
Copy link

给力

@kevwan
Copy link
Contributor

kevwan commented Nov 7, 2021

感谢 @SilverYou

现在跨域可以这么写,从 v1.2.3 开始

srv := rest.MustNewServer(c, rest.WithCors())

如果单个域名可以这么写:

srv := rest.MustNewServer(c, rest.WithCors("http://example.com"))

@mikokutou
Copy link

srv := rest.MustNewServer(c, rest.WithCors())
依然会报跨域错误

@jackluo2012
Copy link
Author

headers = "Content-Type, Content-Length, Origin" 这个里面,加入客户端请求自定义的header ,如 "token,my-token,"看请求里有哪些自定义的,都写上,应该就没问题
如 headers = "Content-Type, Content-Length, Origin,token,my-token"

@xyang0917
Copy link

srv := rest.MustNewServer(c, rest.WithCors()) 依然会报跨域错误

var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}

在Websocket实例中配置下CheckOrigin试试

@fkxgood
Copy link

fkxgood commented Mar 7, 2024

很棒

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

9 participants