You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native国际象棋App安卓端WebSocket 403 Forbidden问题求助

Question: React Native Android WebSocket 403 Forbidden when connecting to Lichess API

I'm developing a chess app with React Native, using WebSocket to handle real-time communication with Lichess API. Everything works perfectly on iOS, but on Android, the WebSocket connection fails with the error: Expected HTTP 101 response but was '403 Forbidden'.

Here's my relevant code for creating a game and establishing the WebSocket connection:

createGame() {
  const { playConfig } = this.props;
  fetch('https://en.lichess.org/setup/ai', {
    method: 'POST',
    headers: {
      Accept: 'application/vnd.lichess.v2+json',
      'Content-Type': 'application/json',
    },
    body: playConfig,
  })
  .then(res => res.json())
  .then(this.onGameCreated);
}

onGameCreated = res => {
  const { game } = this.state;
  const socketUrl = res.url.socket;
  const clientId = Math.random().toString(36).substring(2);
  clearInterval(this.interval);
  this.wsReady = false;
  let url = `wss://socket.lichess.org${socketUrl}?sri=${clientId}&mobile=1`;
  this.ws = new WebSocket(
    url,
  );
  this.ws.onmessage = e => {
    // a message was received
    console.log(`received: ${e.data}`);
    const data = JSON.parse(e.data);
    let moveData;
    let victor;
    if (data.t === 'move' && data.v > game.history().length) {
      moveData = data.d;
    } else if (data.t === 'end') {
      victor = data.d;
    } else if (data.t === 'b') {
      // b for batch
      const first = data.d[0];
      if (first) {
        if (first.d.status && first.d.status.name === 'mate') {
          moveData = first.d;
        }
        if (first.t === 'end') {
          victor = first.d;
        }
        if (first.d.winner) {
          victor = first.d.winner;
        }
      }
    }
    if (victor) {
      dongSound.play();
      this.setState({ victor, });
      this.ws = null;
    } else if (moveData) {
      const { uci, clock } = moveData;
      const castle = moveData.castle;
      let from = uci.substring(0, 2);
      let to = uci.substring(2, 4);
      if (castle && castle.king) {
        from = castle.king[0];
        to = castle.king[1];
      }
      this.board.movePiece(to, from);
      if (clock) {
        this.latestClock = clock;
      }
    }
  };
  this.ws.onerror = e => {
    // an error occurred
    console.log(e.message);
  };
  this.ws.onopen = () => {
    this.wsReady = true;
    dongSound.play();
    this.setState({
      initialized: true,
      userColor: res.player.color === 'white' ? 'w' : 'b',
    });
    console.log('ws open');
    // ping every second
    this.interval = setInterval(
      () => {
        this.sendMessage({ t: 'p', v: game.history().length, });
      },
      1000,
    );
  };
};

Could any developer provide some troubleshooting ideas? Thanks in advance!


Answer

Looks like you're hitting a common cross-platform network discrepancy issue—iOS works fine, but Android's WebSocket gets rejected with a 403. This is almost always due to differences in request headers between the two platforms. Here are the most likely fixes, ordered by priority:

1. Force a Consistent User-Agent for WebSocket Requests

Lichess's server probably validates the User-Agent header, and Android's default WebSocket UA (usually something like okhttp/x.x.x) might be blocked, while iOS uses a Safari-like UA that's allowed.

How to Fix:

Since the native WebSocket constructor doesn't let you set custom headers directly, you have two options:

  • Use a third-party WebSocket library that supports headers: For example, react-native-websocket. Replace your native WebSocket initialization with this, specifying a User-Agent that matches iOS:
    import WebSocket from 'react-native-websocket';
    
    // Inside onGameCreated
    this.ws = new WebSocket(url, [], {
      headers: {
        'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1'
      }
    });
    
  • Globally modify Android's network request UA: Edit your Android native code to add an OkHttp interceptor that sets a consistent User-Agent for all network requests (including WebSocket). In MainApplication.java:
    import okhttp3.OkHttpClient;
    import okhttp3.Interceptor;
    import okhttp3.Request;
    import com.facebook.react.modules.network.OkHttpClientProvider;
    
    @Override
    public void onCreate() {
      super.onCreate();
      OkHttpClient client = OkHttpClientProvider.getOkHttpClient();
      client.interceptors().add(chain -> {
        Request original = chain.request();
        Request modifiedRequest = original.newBuilder()
            .header("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1")
            .build();
        return chain.proceed(modifiedRequest);
      });
    }
    

2. Validate WebSocket URL Parameters

Even though iOS works, double-check that your URL parameters meet Lichess's requirements:

  • Ensure the sri parameter (your clientId) has a valid length/format. Lichess might expect a specific length—try generating a longer string:
    const clientId = Math.random().toString(36).substring(2, 12); // 10-character random string
    
  • Verify that the mobile=1 parameter is correctly appended without encoding issues (your current code looks fine here, but it's worth confirming).

3. Check Android SSL Certificate Configuration

While 403 is a permission error, rare cases of strict SSL certificate validation on Android can cause unexpected issues:

  • Confirm that Lichess's SSL certificate is trusted by Android (public CA certificates are usually trusted by default, so this is unlikely but worth checking).
  • For testing only, temporarily disable SSL validation to rule out certificate issues (never do this in production).

4. Verify Android Network Permissions & Config

Make sure your AndroidManifest.xml includes the required internet permission:

<uses-permission android:name="android.permission.INTERNET" />

If your targetSdkVersion is 28 or higher, confirm that encrypted traffic (wss) is allowed (no need to enable cleartext traffic since you're using secure WebSocket).

Start with the User-Agent fix—it's the most common cause of this exact Android WebSocket 403 error with Lichess, and it should resolve your issue.

内容的提问来源于stack exchange,提问作者Mr.Siadati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:06:27