Proxy `changeOrigin` setting doesn't seem to work - vue.js

I'm using Vue CLI 3.0.0 (rc.10) and am running two servers (backend server and WDS) side by side.
I followed the devServer.proxy instructions on the Vue CLI documentation to add a proxy option to my vue.config.js. I also followed the instructions for the http-proxy-middleware library to supplement the options:
module.exports = {
lintOnSave: true,
outputDir: '../priv/static/',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
ws: true,
},
},
},
};
My understanding is that the changeOrigin: true option needs to dynamically change the Origin header on the request to "http://localhost:4000". However, requests from my app are still being sent from http://localhost:8080 and they trigger CORS blockage:
Request URL: http://localhost:4000/api/form
Request Method: OPTIONS
Status Code: 404 Not Found
Remote Address: 127.0.0.1:4000
Host: localhost:4000
Origin: http://localhost:8080 <-- PROBLEM
What am I doing wrong?

I was having basically the same problem, and what finally worked for me was manually overwriting the Origin header, like this:
module.exports = {
lintOnSave: true,
outputDir: '../priv/static/',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
ws: true,
onProxyReq: function(request) {
request.setHeader("origin", "http://localhost:4000");
},
},
},
},
};

this is my vue.config.js, work fine for me:
module.exports = {
baseUrl: './',
assetsDir: 'static',
productionSourceMap: false,
configureWebpack: {
devServer: {
headers: { "Access-Control-Allow-Origin": "*" }
}
},
devServer: {
proxy: {
'/api': {
target: 'http://127.0.0.1:3333/api/',
changeOrigin: false,
secure: false,
pathRewrite: {
'^/api': ''
},
onProxyReq: function (request) {
request.setHeader("origin", "http://127.0.0.1:3333");
}
}
}
}
}
axios.config.js:
import axios from 'axios';
import { Message, Loading } from 'element-ui'
// axios.defaults.baseURL = "http://127.0.0.1:3333/";
axios.defaults.timeout = 5 * 1000
// axios.defaults.withCredentials = true
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
let loading = null;
function startLoading() {
loading = Loading.service({
lock: true,
text: 'loading....',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.8)'
})
}
function endLoading() {
loading.close()
}
axios.interceptors.request.use(
(confing) => {
startLoading()
// if (localStorage.eToken) {
// confing.headers.Authorization = localStorage.eToken
// }
return confing
},
(error) => {
console.log("request error: ", error)
return Promise.reject(error)
}
)
axios.interceptors.response.use(
(response) => {
endLoading()
return response.data;
},
(error) => {
console.log("response error: ", error);
endLoading()
return Promise.reject(error)
}
)
export const postRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const uploadFileRequest = (url, params) => {
return axios({
method: 'post',
url: url,
data: params,
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
export const getRequest = (url) => {
return axios({
method: 'get',
url: url
});
}
export const putRequest = (url, params) => {
return axios({
method: 'put',
url: url,
data: params,
transformRequest: [function (data) {
let ret = ''
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
}
return ret
}],
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
}
export const deleteRequest = (url) => {
return axios({
method: 'delete',
url: url
});
}
api request:
import {postRequest} from "../http";
const category = {
store(params) {
return postRequest("/api/admin/category", params);
}
}
export default category;
the principle:

According to https://github.com/chimurai/http-proxy-middleware#http-proxy-options, a header option works for me.
devServer: {
proxy: {
'/api': {
target: 'http://127.0.0.1:3333/api/',
headers: {
origin: "http://127.0.0.1:3333"
}
}
}
}

changeOrigin only changes the host header!!!
see the documents http-proxy-middleware#http-proxy-options
option.changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL

Related

Got error 422 with vuex (dispatch) in vuejs

I got an error :
422 (Unprocessable Content)
when I tried to post a data in register form
I have this in my Register.vue
methods: {
register() {
this.$store.dispatch('register', {
firstname: this.firstname,
lastname: this.lastname,
email: this.email,
password: this.password,
});
},
},
};
and in my vuex
actions: {
register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json',
body: JSON.stringify(credentials),
};
console.log(credentials);
return fetch('http://localhost/api/users', requestOptions)
.then((response) => {
return response.json;
})
.catch((err) => console.log(err.message));
},
}
Anyone know where I'm wrong ?
Many thanks
Don't return twice if the request is good.
actions: {
register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json', // not needed
body: JSON.stringify(credentials),
};
console.log(credentials);
return fetch('http://localhost/api/users', requestOptions) // first time
.then((response) => {
return response.json; // second time
})
.catch((err) => console.log(err.message));
},
}
Also use async/await. I'd do
actions: {
async register(credentials) {
const requestOptions = {
method: 'POST',
headers: { 'content-type': 'application/json' },
dataType: 'json',
body: JSON.stringify(credentials),
};
const res = await fetch('http://localhost/api/users', requestOptions);
}
return res.json();
}
And in the Register.vue
methods: {
register() {
this.$store.dispatch('register', {
firstname: this.firstname,
lastname: this.lastname,
email: this.email,
password: this.password,
}).then(data => {
console.log(data)
}).catch((err) => console.log(err.message));
});
},
};
Also you can put it in try/cache etc. It's up to you.
Check the docs, it well explained.

Vuex state array turning an proxy object when it is mutated

I develop a project which gets datas from database. I use Vuex for state management.
Vuex Store File
const store = createStore({
state: {
notUser: {
name: "",
email: '',
password: ''
},
user: {
name: '',
email: '',
messages: [],
about: '',
place: '',
age: '',
role: '',
blocked: false
},
problem: {
title: '',
content: ''
},
problems: [],
errorMessage: {
error: false,
message: '',
success: false
},
},
mutations: {
errorHandler(state, error) {
state.errorMessage.error = true
state.errorMessage.message = error.response.data.message
},
defineUser(state, req) {
state.user = req.data.user
console.log(state.user)
},
getProblems(state, problems) {
state.problems = problems
console.log(state.problems)
}
},
actions: {
register({ commit }, notUser) {
axios({
method: 'post',
url: 'http://localhost:3000/api/auth/register',
data: notUser,
withCredentials: true,
headers: {
"Accept": "application/json"
}
})
.then(res => {
this.state.errorMessage.success = true
console.log(res.data.data.user)
})
.catch(err => {
this.state.errorMessage.success = false
console.log(err.response)
commit('errorHandler', err)
})
},
userLogin({commit}, notUser) {
axios({
method: 'post',
url: 'http://localhost:3000/api/auth/login',
data: notUser,
withCredentials: true,
headers: {
"Accept": "application/json"
}
})
.then(res => {
this.state.user = res.data.data.user
this.state.errorMessage.success = true
console.log(this.state.user)
})
.catch(err => {
this.state.errorMessage.success = false
console.log(err.response)
commit('errorHandler', err)
})
},
checkUser({commit}, access_token) {
axios({
method: 'post',
url: 'http://localhost:3000/api/auth/VpW02cG0W2vGeGXs8DdLIq3dQ62qMd0',
data: access_token,
withCredentials: true,
headers: {
"Accept": "application/json"
}
})
.then(res => {
console.log(res)
commit('defineUser', res)
return true
})
.catch(err => {
console.log(err.response)
commit('errorHandler', err)
return false
})
},
sendProblem({commit}, problem) {
axios({
method: 'post',
url: 'http://localhost:3000/api/problem/add',
data: problem,
withCredentials: true,
headers: {
"Accept": "application/json"
}
})
.then(res => {
console.log(res)
return true
})
.catch(err => {
console.log(err.response)
commit('errorHandler', err)
return false
})
},
getAllProblems({commit}) {
axios({
method: 'get',
url: 'http://localhost:3000/api/problem/getall',
withCredentials: true,
headers: {
"Accept": "application/json"
}
})
.then(res => {
commit('getProblems', res.data.data)
return true
})
.catch(err => {
console.log(err.response)
commit('errorHandler', err)
return false
})
}
// registerUser({commit}, user) {
// commit('register', user)
// }
},
Vue Component: Where Vuex store is being used
computed: {
...mapState(["user", 'problems'])
},
mounted() {
return this.getAll()
},
methods: {
...mapActions(['getAllProblems']),
goToAdd() {
this.$router.push('/add')
},
async getAll() {
this.getAllProblems()
}
}
The problem is when I try to request with getAllProblems action, it should mutate problems variable with getProblems(). Actually it does. But after problems variable changes, it turns something a proxy object. Here are images:
Here is an image of proxy object:
The original data coming from database:
Thanks for comment of #Hasan Hasanova
Okay got it. I called api before website is mounted and used function to get variables from store. The other problem was happened because of using wrong syntax of v-for. Here is the code:
computed: {
allProblems() { // this is the problems array that i was trying to get
return this.$store.state.allProblems
},
loader() {
return this.allProblems == null ? true : false
}
},
beforeMount() {
this.$store.dispatch('getAllProblems', {root: true})
},
And here is the template code :
<div v-if="allProblems.length > 0" class="middle-side">
<div v-for="(problem) in allProblems" :key="problem.id" class="card">
<router-link :to="{ name: 'ProblemDetail', params: { id: problem._id, slug: problem.slug }}">
<div class="card-header">
<div class="card-header-title">
<div class="user-image">
<img src="../../assets/problem.png" />
</div>
<span class="user-name">{{ problem.user.name }}</span>
</div>
...
Thanks for all.
I have the same problem as yours, but I solved it first by converting it before the getter's return, converting it to JSON to string, and converting a string to JSON again before returning it.
const str = JSON.stringify(data)
return JSON.parse(str)
You want to use mapActions to call the action. Then get your data via state, instead of returning the function, since the action is calling a mutation via commit.
computed: {
// you have access to `problems` in the template. Use `v-if` before you `v-for` over the array of problems.
...mapState(["user", 'problems'])
},
mounted() {
this.getAllProblems();
},
methods: {
// ...mapActions(['getAllProblems']),
goToAdd() {
this.$router.push('/add')
}
}
For some reason that happens during the passing of res.data.data to mutations. So if you're expecting a single row result set you should do like:
POPULATE_THIS_STATE_VAR(state, data) {
state.thisStateVar = data[0]
}
... and if you're expecting an array of objects to the result set like what you have, you could do like:
POPULATE_THIS_STATE_VAR(state, data) {
if (data) {
for (let i = 0; i < data.length; i++) {
state.thisStateVar .push(data[i])
}
}
}

NuxtJS Auth Proxy

Then using nuxtjs/auth and nuxtjs/axios nuxt is ignoring my proxy configuration.
In past I have used just axios for auth.
Now I am trying to use the #nuxtjs/auth module. Because I use a seperate backend and CORS I need to use axios proxy for auth.
But the auth stragegy local doesnt use the proxy and I dont get why. It always tries to use the nuxt URL. Seems like auth is absolutely ignoring my proxy. Can anyone help?
// nuxt.config
// ...
axios: {
proxy: true
},
proxy: {
'/api/': {
target: 'http://localhost:4000',
pathRewrite: { '^/api/': '' }
}
},
/*
** Auth Module Configuration
** See https://auth.nuxtjs.org/schemes/local.html
*/
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/api/auth/login', method: 'post', propertyName: 'token' },
logout: { url: '/api/auth/logout', method: 'post' },
user: { url: '/api/auth/user', method: 'get', propertyName: 'user' }
}
}
}
},
// ..
// Component
async userLogin() {
try {
let response = await this.$auth.loginWith('local', { data: this.login })
console.log(response)
} catch (err) {
console.log(err)
}
}
My Nuxt is running on http://localhost:3000
My client always tries to connect to http://localhost:3000/api/auth/login
But I need http://localhost:4000/auth/login
I use all modules up to date
I have same problem. But I use #nuxtjs/auth-next because nuxtjs/auth is outdated and use #nuxtjs/proxy to replace nuxtjs/axios proxy.
Here is my pacakge dependencies.
// pacakge.json
"dependencies": {
"#nuxtjs/auth-next": "^5.0.0-1648802546.c9880dc",
"#nuxtjs/axios": "^5.13.6",
"#nuxtjs/proxy": "^2.1.0",
"nuxt": "^2.15.8",
// ...
}
Fixed nuxt.config.
// nuxt.config.ts
import type { NuxtConfig } from '#nuxt/types';
const config: NuxtConfig = {
ssr: false,
// ...ignore
modules: [
'#nuxtjs/axios',
'#nuxtjs/proxy',
'#nuxtjs/auth-next',
],
auth: {
strategies: {
local: {
name: 'local',
endpoints: {
login: { url: '/api/auth/login', method: 'post', propertyName: 'token' },
logout: { url: '/api/auth/logout', method: 'post' },
user: { url: '/api/auth/user', method: 'get', propertyName: 'user' }
}
// ...ignore
},
},
},
proxy: {
'/api': {
target: 'http://localhost:4000/',
secure: false,
// CORS problem need to set true,
changeOrigin: true,
pathRewrite: {
'^/api' : '/'
}
},
}
};
export default config;
If you set correct, when you run npm run dev the console should show below info.
[HPM] Proxy created: /api -> http://localhost:4000/
[HPM] Proxy rewrite rule created: "^/api" ~> "/"
[HPM] server close signal received: closing proxy server
The proxy object should be outside of the axios object, ie
axios: {
proxy: true,
// Your other configurations
}
proxy: {
'/api/': {
target: 'http://localhost:4000',
pathRewrite: { '^/api/': '' }
}
}

webpack-dev-server does not properly proxy redirect to the backend with hapi and and hapi-auth-cookie

When i boot up the hapi-server as well as the webpack-dev-server and go to localhost:3000/api/login shows a 502 bad gateway and nothing on the page! Thanks for every one who helps
Here is my webpack file:
module.exports = {
entry: ["./index.js"],
output: {
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: {
index: 'index.html'
},
stats: 'normal',
host: process.env.HOST || 'localhost',
port: process.env.PORT || 3000,
proxy: {
'/api/*': {
target: 'http//localhost:9000',
secure: false
}
}
}
};
Here is my hapi-server:
const Hapi = require('hapi');
const Inert = require('inert');
const config = require('./config');
const CookieAuth = require('hapi-auth-cookie');
const server = new Hapi.Server();
server.connection({port: 9000});
const options = {
ops: {
interval: config.hapiGoodInterval
},
reporters: {
console: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ log: '*', response: '*' }]
}, {
module: 'good-console'
}, 'stdout'],
file: [{
module: 'good-squeeze',
name: 'Squeeze',
args: [{ ops: '*' }]
}, {
module: 'good-squeeze',
name: 'SafeJson'
}, {
module: 'good-file',
args: ['./logs/fixtures/file_log']
}]
}
};
server.register(CookieAuth, (err) => {
if (err) {
throw err;
}
});
server.register(Inert, ()=>{});
server.register({
register: require('good'),
options,
}, (err) => {
if (err) {
return console.error(err);
}
server.start(() => {
console.info(`Server started at ${ server.info.uri }`);
});
});
const cache = server.cache({ segment: 'sessions', expiresIn: 3 * 24 * 60 * 60 * 1000 });
server.app.cache = cache;
server.auth.strategy('session', 'cookie', true, {
password: 'Vaj57zED9nsYeMJGP2hnfaxU874t6DV5',
cookie: 'sid-example',
redirectTo: '/api/login',
isSecure: false,
validateFunc: function (request, session, callback) {
cache.get(session.sid, (err, cached) => {
if (err) {
return callback(err, false);
}
if (!cached) {
return callback(null, false);
}
return callback(null, true, cached.account);
});
}
});
server.route(require('./routes'));
Here are the routes:
var Handlers = require('./handlers');
var Joi = require('joi');
var Routes = [
{
path: '/api/hello',
method: 'GET',
config: {
auth:false,
handler: function (request, reply) {
reply('Hello from the server')
}
}
},
{
method: ['GET', 'POST'],
path: '/api/login',
config: {
handler: Handlers.login,
auth: { mode: 'try' },
plugins: {
'hapi-auth-cookie': { redirectTo: false }
}
}
},
{
path: '/api/logout',
method: 'GET',
handler: Handlers.logout
}
];
And Finally the handlers:
const r = require('rethinkdb');
var {Post, User, Opinion} = require('./rethinkdb/models/all');
class Handlers {
static login(request, reply) {
let username = 'pesho';
let password = '12345';
let uuid = 1;
if (request.auth.isAuthenticated) {
return reply.redirect('/');
}
let message = '';
let account = null;
if (request.method === 'post') {
if (!request.payload.username ||
!request.payload.password) {
message = 'Missing username or password';
}
else {
if (password !== request.payload.password || username !== request.payload.username) {
message = 'Invalid username or password';
}
}
}
if (request.method === 'get' || message) {
return reply('<html><head><title>Login page</title></head><body>' +
(message ? '<h3>' + message + '</h3><br/>' : '') +
'<form method="post" action="/api/login">' +
'Username: <input type="text" name="username"><br>' +
'Password: <input type="password" name="password"><br/>' +
'<input type="submit" value="Login"></form></body></html>');
}
const sid = String(++uuid);
request.server.app.cache.set(sid, { account: account }, 0, (err) => {
if (err) {
reply(err);
}
request.cookieAuth.set({ sid: sid });
return reply.redirect('/');
});
}
static logout(request, reply) {
request.cookieAuth.clear();
return reply.redirect('/');
};
}
module.exports = Handlers;
The problem was kind-a dump, but here it is:
you must add a "/" at the end of the proxy target
proxy: {
'/api/*': {
target: 'http://localhost:9000/',<= This here
secure: false
}
},

hapi-auth-cookie is protecting all routes, including static

Without applying a strategy to any routes, hapi-auth-cookie is protecting all routes, including static.
server.register(require('hapi-auth-cookie'), function (err) {
if (err) {
logError(err);
}
server.auth.strategy('session', 'cookie', true, {
password: 'things really long',
clearInvalid: true,
isSecure: false,
validateFunc: function (request, session, callback) {
cache.get(session.sid, (err, cached) => {
if (err) {
return callback(err, false);
}
if (!cached) {
return callback(null, false);
}
return callback(null, true, cached.account);
});
}
});
});
Here are my routes:
{
method: 'POST',
path: '/api/1/doSomething',
config: {
validate: {
payload: someJoyObject
},
handler: function(request, reply) {
stuff
}
}
}
and
{
method: 'GET',
path: '/{param*}',
handler: {
directory: {
path: './public',
listing: false,
index: true
}
}
}
I can't load any files of my app:
{"statusCode":401,"error":"Unauthorized","message":"Missing authentication"}
Have a look at the documentation for server.auth.strategy(). You're passing true as the 3rd argument meaning hapi will apply this strategy to all routes by default.
To disable it for your static routes either:
Don't set it as a required strategy for all routes
Disable the strategy explicitly on your directory handler route:
e.g.:
{
method: 'GET',
path: '/{param*}',
config: {
auth: false
},
handler: {
directory: {
path: './public',
listing: false,
index: true
}
}
}