Add more options for proxy context
deraw opened this issue · 16 comments
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'
}
}
}
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 !
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.
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.
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!
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).
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/'
}
}
}
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-
@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!
I think I found out where the problem is.
vue-cli/packages/@vue/cli-service/lib/util/prepareProxy.js
Lines 62 to 84 in d88f2fa
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
)
},
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:
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/
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
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 @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.
has any idea for change request header’s content when start proxy??
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