express代理转发请求

在浏览器中,我们使用js发送ajax请求非当前域名的服务器时,是有跨域的问题的。 也就是说,如果我们在js里请求第三方服务器是会被浏览器拦截,导致请求失败。 这个问题有两种解决方案:

  • 请求的第三方服务器设置response的header,对响应头不要限制请求方法。

  • 通过请求自己的服务器,服务器代理这个请求转发出去。

第一种通常我们可能没有去操作的权限。 通常我们会使用第二种,因为我们对自己的服务器有充分的权限。 如果是express的后台,我们需要注意几个点,才能顺利的完成整个代理流程。 先看看代码:

http = require 'http'
url = require 'url'
_ = require 'underscore'
queryString = require 'querystring'

module.exports = (options) ->

  return (req, res, next) ->
    # 查找符合规则的代理配置
    k = _.chain(options).keys().find (k) ->
      req.url.match new RegExp(k)
    .value()
    unless k
      next()
    else
      server_config = options[k]
      #get the right url from routing
      if k != req.url
        # find in the route's definition
        if k.indexOf('*') > 0
          regex = new RegExp(k.replace('*', '(.+)'));
          path = regex.exec(req.url);
          server_config = server_config.replace('*', path.splice(1)) if path
      console.log "proxy #{req.url} to remote service #{server_config}"
      req_opt = url.parse server_config
      # TODO handle error event to avoid exit with error because of wrong proxy
      # console.log "#{JSON.stringify(req_opt)}"
      console.log req.body
      req_options = {
        hostname: req_opt.hostname
        port: req_opt.port
        path: req_opt.path
        method: req.method
        headers: {}
      }
      request = http.request req_options
      , (response) ->
        res.writeHead response.statusCode, response.headers
        response.pipe(res)
        response.on 'data', (data) ->
          console.log "代理转发[服务器]响应: #{response.statusCode}, #{data.toString()}"

        response.on 'error', (e) ->
          console.log 'problem with response: ' + e.message
      #catch exception
      request.on 'error', (e) ->
        console.log "error happend when write to the background server, #{e}"
      request.write(queryString.stringify(req.body))
      request.end()
      req.on 'error', (e) ->
        console.log 'problem with request: ' + e.message

      req.on 'end', ->
        request.end()

这是coffee代码,主要逻辑就是:拦截请求——>匹配需要代理的请求——>组装代理请求http.request——>设置request的参数——>发送请求——>得到的响应结果返回. 需要注意两个点:

  • 代理请求的options的headers不能使用前请求的req.headers,这样会导致直接返回404,原因没详查。因此这里就填了{}

  • 代理转发的写入时需要使用到body-parser这个插件否则读取req.body是空的。这个在配置express的时候使用即可。

Table of Contents