vuejs / vue-cli

🛠️ webpack-based tooling for Vue.js Development
https://cli.vuejs.org/
MIT License
29.75k stars 6.33k forks source link

Add more options for proxy context #2320

Open deraw opened 6 years ago

deraw commented 6 years ago

What problem does this feature solve?

In the docs for devServer.proxy, you link to this documentation : https://github.com/chimurai/http-proxy-middleware#context-matching, which contains multiple options for context maching, like exculsion, wich, I think, would be nice to have !

What does the proposed API look like?

// vue.config.js
devServer: {
    index: '',
    proxy: {
        '!\/dist\/*': {
            target: 'http://127.0.0.1:8000'
        }
    }
}
deraw commented 6 years ago

I've juste made a small plugin https://www.npmjs.com/package/@deraw/vue-cli-plugin-proxy to fix my issue, but it would still be nice to have this by default !

aldencolerain commented 6 years ago

I had a really hard time with the proxy settings, there are a number of bugs. Its also a bit confusing that the docs link to http-proxy-middleware but vue clie re-writes your options and they are subtly different. Maybe it just needs to be documented a little better but on first read it does seem like the proxy settings are 1 to 1 with the webpack proxy settings but they aren't.

jpicton commented 5 years ago

Couldn't agree with @aldencolerain more. After reading https://cli.vuejs.org/config/#devserver-proxy I fully expected the devServer/proxy property to be compatible with all the http-proxy-middleware options.

Even when I realised that wasn't the case and the devServer/proxy property format was too restrictive for what I wanted to achieve, I couldn't even eschew it entirely and configure devserver via the chainWebpack property instead because it looks like anything devserver related you configure via the webpack properties is overwritten by vue-cli. Really shouldn't be this hard.

deraw commented 5 years ago

Hey @aldencolerain and @jpicton! I've published v2 of the vue-cli-plugin-proxy, which introduce pluginOptions, that means that you can pass any context and any options, in a simply and elegant way, try it out!

woodcoder commented 5 years ago

I've just migrated from a previous vue cli template setup where I was using the proxyTable with the filter option to do this sort of url matching (see old docs).

Like the other commenters above, I had a similar misreading of the documentation for devServer.proxy and only by looking at the source for prepareProxy did I realise that it was wrapping the context and therefore wasn't providing the same functionality as either the http-proxy-middleware or the webpack dev server documentation.

I'd like to see support for a context property, like in the webpack dev server, that you could provide the more complicated micromatch style matches, or a function, to. Something like:

devServer: {
  proxy: {
    default: {
      context: ['/auth', '/api'],
      target: 'http://127.0.0.1:3000'
    }
  }
}

The top-level property name (in this case, default) which usually contains a simple path match is ignored in favour of the value context. As with the webpack dev server proxy, this could perhaps just be an array if the context is supplied (see #2285).

FFGF commented 5 years ago

you can write as follow
devServer: { proxy: { '/getAbc|/getSde|/getCde': { target: 'http://127.0.0.1:3000/avc/', }, '/initQwer': { target: 'http://127.0.0.1:3000/def', }, '/getCvf': { target: 'http://127.0.0.1:3000/efd/' } } }

tychenjiajun commented 5 years ago

Is it possible to use custom matching? For example, I only want to proxy GET method

/**
 * @return {Boolean}
 */
var filter = function(pathname, req) {
  return pathname.match('^/api') && req.method === 'GET'
}

var apiProxy = proxy(filter, { target: 'http://www.example.org' })

@Deraw-

deraw commented 5 years ago

@tychenjiajun Yes it is possible with the plugin!

Uner the hood, it does

proxy(
    options.pluginOptions.proxy.context,
    options.pluginOptions.proxy.options
)

In the code you posted, filter is the context, and { target: 'http://www.example.org' } is your option object.

So you could use it like this:

// vue.config.js
var filter = function(pathname, req) {
  return pathname.match('^/api') && req.method === 'GET'
}

module.exports = {
  pluginOptions: {
    proxy: {
      context: filter,
      options: {
        target: 'http://www.example.org'
      }
    }
  }
}

And it should work!

dousybox commented 5 years ago

I think I found out where the problem is.

https://github.com/vuejs/vue-cli/blob/d88f2faf64e7fa75ad0ac14bf897f81214d2e3dd/packages/%40vue/cli-service/lib/util/prepareProxy.js#L62-L84

Is there any reason need forced handle the context match?

Or we can just let the http-proxy-middleware do what it should have done, if there was a context parameters.

      context: context || function (pathname, req) {
        // is a static asset
        if (!mayProxy(pathname)) {
          return false
        }
        // not a static request
        if (req.method !== 'GET') {
          return true
        }
        // Heuristics: if request `accept`s text/html, we pick /index.html.
        // Modern browsers include text/html into `accept` header when navigating.
        // However API calls like `fetch()` won’t generally accept text/html.
        // If this heuristic doesn’t work well for you, use a custom `proxy` object.
        return (
          req.headers.accept &&
          req.headers.accept.indexOf('text/html') === -1
        )
      },
p-m-j commented 4 years ago

At the very least you could change the following to make it clear that it's wrapped and might not work as expected,

https://cli.vuejs.org/config/#devserver-proxy

If you want to have more control over the proxy behavior, you can also use an object with path: options pairs. Consult http-proxy-middleware for full options:

ejez commented 4 years ago

To pass the context as a regular expressions, we can use something similar to:

  devServer: {
    proxy: {
      ['^(?!/static/bundles/)']: {
        target: 'http://localhost:8000'
      }
    }
  }

The above example will proxy all requests not starting with /static/bundles/

daveykane commented 4 years ago
var filter = function(pathname, req) {
  return pathname.match('^/api') && req.method === 'GET'
}

module.exports = {
  pluginOptions: {
    proxy: {
      context: filter,
      options: {
        target: 'http://www.example.org'
      }
    }
  }
}

Hi @deraw,

With the plugin is it possible to have different targets for different contexts?

Thanks

deraw commented 4 years ago

Hi @daveykane,

Sorry for late reply. I think it's possible since the plugin juste passes the options to http-proxy-middleware! (But I didn't test it manually)

daveykane commented 4 years ago

Hi @daveykane,

Sorry for late reply. I think it's possible since the plugin juste passes the options to http-proxy-middleware! (But I didn't test it manually)

Hi @deraw,

No worries, thanks for getting back to me. I have managed to get it working by passing the router option. Originally I was trying/wondering if it were possible to set an array of objects, each with a context and target, similarly to how you can setup the config in the webpack dev server proxy but I realised your plugin would need to be looping that array and calling proxy() on each.

I instead used router as a workaround and it seems to work as expected, thanks again.

anming-john commented 4 years ago

has any idea for change request header’s content when start proxy??

tojoirinah commented 3 years ago

I'm using VueJS 2.x, how to change this proxy target dynamically from json file for example ? So we won't need to build every we want to change proxy url but only the json file