草庐IT

go - 将上下文从 Web 请求的 Controller 传递到数据库层

coder 2023-07-02 原文

我有 REST 服务:

  • 每个请求都有一个带有 JWT token 的 header
  • 每个 Controller 从请求中获取参数(变量,主体..)并将它们传递给数据层

我需要将 JWT token 从每个请求的 header 传递到相应的数据层方法中,如下所示:

func (a *App) UpdateOrder(_ http.ResponseWriter, r *http.Request) (interface{}, error) {

    bodyData := new(models.Order)
    err = json.NewDecoder(r.Body).Decode(&bodyData)
    if err != nil {
       return nil, err
    }

    user, err := a.Saga.GetUserByToken(r.Header.Get("Authorization"))  // here
    // error handling ...

    a.DbLayer.UpdateOrder(id, bodyData, user)  // and there
}

在这种情况下,我必须为每个 Controller 编写相同的代码以通过 token 获取用户,并将该用户显式传递给数据库层。

有没有办法为每个请求传递这个用户,而无需在每个 Controller 中编写此代码?

我知道中间件,我可以在我的中间件中通过 token 获取用户。但是我怎样才能将这个用户从中间件传递到相应的数据库级方法呢?

可能我正在为 goroutine 寻找类似“全局变量”的东西?我可以在我的中间件中获取用户并将其设置为“全局变量”之类的东西。我可以在数据库层得到这个“全局变量”的值。但必须是当前web请求的“全局变量”,并发web请求不能相互影响。

在 Go、http 模块或 gorilla\mux 中是否有某种机制来实现我所说的“全局变量”?

最佳答案

你在描述上下文。

最初有 gorilla context package ,它提供了一个伪全局上下文对象 - 本质上是一个 map[interface{}]interface{},其中包含对中间件/ Controller /数据层堆栈中的所有参与者本质上可用的引用。

除了来自 an excellent guide to the package 之外,请参阅此内容(所有功劳归功于作者 Matt Silverlock)。

type contextKey int

// Define keys that support equality.
const csrfKey contextKey = 0
const userKey contextKey = 1

var ErrCSRFTokenNotPresent = errors.New("CSRF token not present in the request context.")

// We'll need a helper function like this for every key:type
// combination we store in our context map else we repeat this
// in every middleware/handler that needs to access the value.
func GetCSRFToken(r *http.Request) (string, error) {
    val, ok := context.GetOk(r, csrfKey)
    if !ok {
        return "", ErrCSRFTokenNotPresent
    }

    token, ok := val.(string)
    if !ok {
        return "", ErrCSRFTokenNotPresent
    }

    return token, nil
}

// A bare-bones example
func CSRFMiddleware(h http.Handler) http.Handler {
    return func(w http.ResponseWriter, r *http.Request) {
        token, err := GetCSRFToken(r)
        if err != nil {
            http.Error(w, "No good!", http.StatusInternalServerError)
            return
        }

        // The map is global, so we just call the Set function
        context.Set(r, csrfKey, token)

        h.ServeHTTP(w, r)
    }
}

在 gorilla 包启动后,一个 context package被添加到标准库中。它略有不同,因为上下文不再是伪全局的,而是从一个方法传递到另一个方法。在这种情况下,上下文附加到初始请求 - 可通过 request.Context 获得。处理程序下方的层可以接受上下文值作为其签名的一部分,并从中读取值。

这是一个简化的例子:

type contextKey string

var (
    aPreSharedKey = contextKey("a-preshared-key")
)

func someHandler(w http.ResponseWriter, req *http.Request) {
    ctx := context.WithValue(req.Context, aPreSharedKey, req.Header.Get("required-header"))
    data, err := someDataLayerFunction(ctx)
    if err != nil {
        fmt.Fprintf(w, "uhoh", http.StatusBadRequest)
        return
    }
    fmt.Fprintf(w, data, http.StatusOK)
}

func someDataLayerFunction(ctx context.Context) (string, error) {
    val, ok := ctx.Value(aPreSharedKey).(string)
    if !ok {
        return nil, errors.New("required context value missing")
    }
    return val
}

有关更多详细信息和不那么做作的示例,请查看谷歌的 excellent blog on the context package's use.

关于go - 将上下文从 Web 请求的 Controller 传递到数据库层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51337490/

有关go - 将上下文从 Web 请求的 Controller 传递到数据库层的更多相关文章

  1. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  2. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  3. ruby-on-rails - rails : How to make a form post to another controller action - 2

    我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

  4. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  5. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  6. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  7. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  8. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  9. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  10. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

随机推荐