2

I have a simple client running in React. I am trying to make a GET request using Axios to a Go server that I have running locally. The React code is running on port 3000, the Go server on 4000.

If I paste the GET request itself in the browser window it works fine: http://localhost:4000/numberconverter?number=10&oldBase=10&newBase=2

I've done some research and found this post, but the plugin and the Chrome options do not help. That isn't the only research I've done, but that seemed to be the most promising. Most of the stuff I've found doesn't involve a Go server.

I've also found this post, but that also did not solve my problem. If I uncomment the code in the server it still fails.

If I change the allowed methods to:

writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS")

It fails with a 405 error. The server prints out this:

&{0xc4200f4000 0xc42000a500 {} 0x10ec430 true false false false 0xc4200143c0 {0xc420100000 map[Access-Control-Allow-Origin:[*] Access-Control-Allow-Methods:[GET, POST, PATCH, PUT, DELETE, OPTIONS] Content-Type:[text/plain; charset=utf-8] X-Content-Type-Options:[nosniff]] false false} map[Access-Control-Allow-Origin:[*] Access-Control-Allow-Methods:[GET, POST, PATCH, PUT, DELETE, OPTIONS] Content-Type:[text/plain; charset=utf-8] X-Content-Type-Options:[nosniff]] true 19 -1 405 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] 0xc4200620e0 0}

I guess my question is whether this is a problem on the server side or the client side as well as how could I fix the problem?

Client:

import React, {Component} from 'react';
import axios from 'axios';

class Converter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            // number: 0,
            // base: 10,
            // newBase: 10
        };
        this.convertButtonPressed = this.convertButtonPressed.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState({
        [name]: value
        });
    }

    convertButtonPressed(event) {
        axios({
            method: 'GET',
            baseURL: 'http://localhost:4000/',
            url: '/numberconverter',
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
                'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token'
            },
            params: {
            number: this.state.number,
            oldBase: this.state.base,
            newBase: this.state.newBase
            }
        });
    }

    render() {
        return (
        <div className="App">
            <p>Number Converter</p>
            <div>
            Number:
            <input name="number" onChange={this.handleChange} type="text" placeholder="Number"></input><br />
            Base:
            <input name="base" onChange={this.handleChange} type="text" placeholder="Base"></input><br />
            New Base:
            <input name="newBase" onChange={this.handleChange} type="text" placeholder="New Base"></input><br />
            </div>
            <button onClick={this.convertButtonPressed}>Convert</button>
        </div>
        );
    }
}

export default Converter;

Server:

package rest

// Example:
// http://localhost:3000/numberconverter?number=500000&oldBase=10&newBase=16

import (
    "fmt"
    "log"
    "net/http"

    "../converter"
)

// Start starts the server
func Start() {
    //muxRouter := http.NewServeMux()
    //muxRouter.HandleFunc("/numberconverter", numberconverter)
    //http.Handle("/", muxRouter)
    http.HandleFunc("/numberconverter", numberconverter)
    log.Fatal(http.ListenAndServe(":4000", nil))
}

func numberconverter(writer http.ResponseWriter, response *http.Request) {
    //writer.Header().Set("Access-Control-Allow-Origin", "*")
    //writer.Header().Set("Access-Control-Allow-Methods", "*")
    //writer.Header().Set("Content-Type", "text/html; charset=utf-8")

    // Check if the method is a get
    if response.Method != http.MethodGet {
        http.Error(writer, http.StatusText(405), 405)
        fmt.Println(writer)
        return
    }

    number := response.FormValue("number")
    oldBase := response.FormValue("oldBase")
    newBase := response.FormValue("newBase")
    result := converter.ConvertStringNumberToNewBase(number, oldBase, newBase)
    fmt.Fprintf(writer, "%s base %s is %s in base %s", number, oldBase, result, newBase)
}
sideshowbarker
  • 62,215
  • 21
  • 143
  • 153
Mojo982
  • 117
  • 1
  • 10
  • Does it work if you uncomment those header setting lines? Browser extensions are absolutely the wrong way to solve this. None of your users will have them. – captncraig Aug 31 '17 at 15:40
  • IIRC, `Access-Control-Allow-Methods` can't be `*`. It should be a list of methods. – Ainar-G Aug 31 '17 at 15:43
  • Possible duplicate of [Setting HTTP headers](https://stackoverflow.com/questions/12830095/setting-http-headers) – captncraig Aug 31 '17 at 15:44
  • @captncraig if I uncomment those lines it still does not work. Those lines are from me attempting to fix the issue. – Mojo982 Aug 31 '17 at 15:46
  • @captncraig I also found that link and that's where I got the commented out code. – Mojo982 Aug 31 '17 at 15:47
  • @Ainar-G I'll add a response to your comment in the post. – Mojo982 Aug 31 '17 at 15:52
  • Remove `headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token' }` from your frontend JavaScript code. Those headers are all strictly *response* headers for servers to send back in response to requests. The only effect that adding to them to your frontend JavaScript code will have is to break things – sideshowbarker Aug 31 '17 at 16:58
  • 1
    Those headers your frontend code adds trigger your browser to automatically on its own do a COR preflight OPTIONS request before trying the GET request your code is intended to send https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests And because in the backend code of the server you’re sending the request to, you have it do `if response.Method != http.MethodGet { http.Error(writer, http.StatusText(405), 405) …}`, that gets hit when the browser sends the preflight OPTIONS & the preflight fails & your browser never moves on to trying the GET from your code – sideshowbarker Aug 31 '17 at 17:04

1 Answers1

0

Once I commented out the headers in the React code the GET request worked. I'd like to thank sideshowbarker for the answer. I really appreciate it.

convertButtonPressed(event) {
    axios({
        method: 'GET',
        baseURL: 'http://localhost:4000/',
        url: '/numberconverter',
        // headers: {
        //     'Access-Control-Allow-Origin': '*',
        //     'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
        //     'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token'
        // },
        params: {
          number: this.state.number,
          oldBase: this.state.base,
          newBase: this.state.newBase
        }
      });
}
Mojo982
  • 117
  • 1
  • 10