4

Following the Axios NuxtJS config, I created a proxy config like this on my nuxt.config.js:

  proxy: {
    '/api/': {
      target: 'https://myapidomain.com/',
      pathRewrite: { '^/api/': '' },
      changeOrigin: true
    }
  }

This config works perfectly on dev environment, both server side rendering and client side rendering. Here is the code we use to create an api wrapper api.js:

export default (context, inject) => {
  inject('api', {
    getPageForSlug: (slugRoute) => {
      return context.$axios.$get(`/api/pageForSlug?routeName=${slugRoute}`)
    },
  })
}

and then from any vue class:

const response = await app.$api.getPageForSlug(params.slug_route)

the only problem occurs when this code is called from the zeit now deployment. The client side works perfectly, but the server side returns this error:

START RequestId: dd92dbad-135f-414b-bc1d-df9faffaa681 Version: $LATEST
2019-08-30T17:46:03.098Z    dd92dbad-135f-414b-bc1d-df9faffaa681    INFO    λ Cold start took: 5265.617811ms
END RequestId: dd92dbad-135f-414b-bc1d-df9faffaa681
REPORT RequestId: dd92dbad-135f-414b-bc1d-df9faffaa681  Duration: 438.53 ms Billed Duration: 500 ms     Memory Size: 3008 MB    Max Memory Used: 92 MB  

N',
     xsrfHeaderName: 'X-XSRF-TOKEN',
     maxContentLength: -1,
     validateStatus: [Function: validateStatus],
     data: undefined },
  request:
   Writable {
     _writableState:
      WritableState {
        objectMode: false,
        highWaterMark: 16384,
        finalCalled: false,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        destroyed: false,
        decodeStrings: true,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        corked: 0,
        sync: true,
        bufferProcessing: false,
        onwrite: [Function: bound onwrite],
        writecb: null,
        writelen: 0,
        bufferedRequest: null,
        lastBufferedRequest: null,
        pendingcb: 0,
        prefinished: false,
        errorEmitted: false,
        emitClose: true,
        autoDestroy: false,
        bufferedRequestCount: 0,
        corkedRequestsFree: [Object] },
     writable: true,
     domain: null,
     _events:
      [Object: null prototype] { response: [Function], error: [Function] },
     _eventsCount: 2,
     _maxListeners: undefined,
     _options:
      { protocol: 'http:',
        maxRedirects: 21,
        maxBodyLength: 10485760,
        path: '/api/pageForSlug?routeName=lud_form',
        method: 'GET',
        headers: [Object],
        agent: undefined,
        auth: undefined,
        hostname: 'localhost',
        port: '3000',
        nativeProtocols: [Object],
        pathname: '/api/pageForSlug',
        search: '?routeName=lud_form' },
     _redirectCount: 0,
     _redirects: [],
     _requestBodyLength: 0,
     _requestBodyBuffers: [],
     _onNativeResponse: [Function],
     _currentRequest:
      ClientRequest {
        domain: null,
        _events: [Object],
        _eventsCount: 6,
        _maxListeners: undefined,
        output: [],
        outputEncodings: [],
        outputCallbacks: [],
        outputSize: 0,
        writable: true,
        _last: true,
        chunkedEncoding: false,
        shouldKeepAlive: false,
        useChunkedEncodingByDefault: false,
        sendDate: false,
        _removedConnection: false,
        _removedContLen: false,
        _removedTE: false,
        _contentLength: 0,
        _hasBody: true,
        _trailer: '',
        finished: true,
        _headerSent: true,
        socket: [Socket],
        connection: [Socket],
        _header:
         'GET /api/pageForSlug?routeName=lud_form HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nx-now-deployment-url: lps-5fxmi58fz.now.sh\r\nx-now-trace: staging-gru1\r\nx-real-ip: 177.45.65.235\r\nx-zeit-co-forwarded-for: 177.45.65.235\r\nupgrade-insecure-requests: 1\r\nx-forwarded-proto: https\r\nx-now-id: 7xllz-1567187175018-d0ce35475a9e\r\naccept-encoding: gzip, deflate\r\nuser-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36\r\nx-forwarded-for: 177.45.65.235\r\nx-forwarded-host: lps-danicuki.playax.now.sh\r\ndnt: 1\r\naccept-language: en-US,en;q=0.9\r\nconnection: close\r\nHost: localhost:3000\r\n\r\n',
        _onPendingData: [Function: noopPendingOutput],
        agent: [Agent],
        socketPath: undefined,
        timeout: undefined,
        method: 'GET',
        path: '/api/pageForSlug?routeName=lud_form',
        _ended: false,
        res: null,
        aborted: undefined,
        timeoutCb: null,
        upgradeOrConnect: false,
        parser: null,
        maxHeadersCount: null,
        _redirectable: [Circular],
        [Symbol(isCorked)]: false,
        [Symbol(outHeadersKey)]: [Object] },
     _currentUrl: 'http://localhost:3000/api/pageForSlug?routeName=lud_form' },
  response: undefined,
  isAxiosError: true,
  toJSON: [Function] }
END RequestId: 6e355938-32d5-459a-adf7-08fb97101e29
REPORT RequestId: 6e355938-32d5-459a-adf7-08fb97101e29  Duration: 281.53 ms Billed Duration: 300 ms     Memory Size: 3008 MB    Max Memory Used: 117 MB 
RequestId: 6e355938-32d5-459a-adf7-08fb97101e29 Error: Runtime exited with error: exit status 1
Runtime.ExitError 

How to make the server side API request work on all environments?

Daniel Cukier
  • 11,502
  • 15
  • 68
  • 123

2 Answers2

2

This can be achieved using a rewrite in your now.json Vercel file. No need for a hack.

{
  "version": 2,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder",
      "config": {}
    }
  ],
  "rewrites": [
    {
      "source": "/api/:match*",
      "destination": "https://myapidomain.com/:match*"
    }
  ]
}
Thijs
  • 568
  • 6
  • 16
0

Are you ready for the ultimate hack?

This is actually a common issue. When calling zeit now, a server doesn't actually get propped up. As such, you'll need to do it yourself.

The only time I've encountered a need to do this, I used express to solve it. A quick and dirty solution is to create another script (proxy.js), and have something like so:

import express from 'express'
import proxy from 'express-http-proxy'
const app = express()
app.use('/', proxy(`https://myapidomain.com`))
export default app

This does nothing but set up a reverse proxy to your API.

From there, in your zeit config, find your builds key if you have one, and replace it with this:

"builds": [
    { "use": "@now/next", "src": "package.json" },
    { "use": "@now/node", "src": "proxy.js" }
]

This will prop up and execute proxy.js when you build using zeit now.

Do note that this does mean you'll need to get the host in proxy.js to match the "normal" host. If you know the format of your config file (which you should), it may be possible to import and parse that in order to have one source of truth.

Let me know if this worked.

Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
  • I did exactly what you described but the error is still the same. Here is my now.json: `{ "version": 2, "builds": [ { "src": "nuxt.config.js", "use": "@nuxtjs/now-builder", "config": {} }, { "use": "@now/node", "src": "proxy.js" } ] }` – Daniel Cukier Sep 03 '19 at 00:25
  • 1
    I am running against the same issue but your solution does not work for me.. i keep running against 502: BAD_GATEWAY on now.sh using a proxy or having cors issue's without using a proxy. – Bananenspin Dec 10 '19 at 19:17